Sefx C Language Sound Effects Library Version 1.0 20 Feb 92 Copyright (c) 1992 Bri Productions 1 Table of Contents Introduction Acknowledgments.........................4 General Description.....................4 Disclaimer..............................4 Registration............................4 Contacting the Author...................5 Terminology.............................5 A typedef...............................5 Control Functions Description.............................6 SndOpen.................................7 SndClose................................8 SndLen..................................9 SndTbase...............................10 SndFlush...............................11 SndHold................................12 SndTerm................................13 Sound Generation Functions Description............................14 SndTone................................15 SndPause...............................16 SndString..............................17 SndTrill...............................18 SndSlide...............................19 SndPulse...............................20 2 Miscellaneous SndMs..................................21 Appendix A - Things to look out for............22 Appendix B - Musical notes.....................23 Appendix C - Sound queue usage.................24 Appendix D - Registration form.................25 3 Acknowledgments. I would like to thank Earl Jensen for technical review and advice, James Garcia for musical information and Margaret Carlsen for proof reading this documentation. General Description. Sefx is a C language timer-driven sound effects library for IBM and compatible computers. Sefx is compatible with most if not all DOS based C compilers. All the sound generated by Sefx is generated in the background. This fact allows the program to continue with other operations while the sound is generated. Some of Sefx's features are: ù Generates sound simultaneously to other operations ù Produces frequencies from 19 to 20,000+ hertz ù Time bases of 54.9, 27.5, 13.7 and 6.9 milliseconds ù Changes frequency up to 145 time per second ù Adjustable sound queue as large as 65532 bytes ù Sound queue is handled internally ù Written in assembly language for optimum speed and efficiency. DISCLAIMER. Sefx is provided AS IS. Bri Productions specifically disclaims any and all warranties, expressed or implied, including fitness for a particular purpose. Use this product at your own risk. Registration. Sefx is a user supported software product. Distribution of this product, unaltered and without charge, is encouraged. If you find this product useful, you are encouraged to register your copy. This allows Bri Productions to continue to provide support low cost, high quality shareware. The registration fee is $25.00 US dollars and includes libraries for small, medium, compact and large memory models and complete source code. A registration form is provided in Appendix D. 4 Contacting the author. Bri Productions may be contacted by any of the following means: U.S. mail - Bri Productions P.O.Box 7121 Fremont, CA 94537-7121 Phone - (510) 794-0616 CompuServe - 76635,2246 CompuServe is a trademark of CompuServe Inc. Terminology This section is intended to define the terminology used in this documentation and clarify any ambiguities thereof. A 'tone' consists of a single frequency and a 'duration'. A 'pause' is the same in all respects as a 'tone' except for the absents of a frequency. It can also be defined as a 'tone' with a frequency of zero. A 'sound' is one or more 'tones' and/or 'pauses' put together to produce the desired results. ie. trill, slide, string, etc. A 'sound' may consist of only one 'tone' or 'pause'. Each Sefx sound generation function generates exactly one sound. The 'time base' refers to the length of time of one 'tic' which is the basic unit of time used by the Sefx sound generating functions. A new 'tone' or 'pause' may be loaded as often as once per 'tic'. Hence the frequency may be changed as often as the value of the 'time base'. The 'duration' of a 'tone' is the number of 'tics' (and hence the length of time) it will last. Examples: A 'tone' with a 'duration' of two 'tics', when the 'time base' is set to MEDium (27.5ms), will last 55 milliseconds. A 'sound' consisting of a 'tone' with a 'duration' of of two 'tics', a 'pause' with a 'duration' of one 'tic' followed by another tone with a 'duration' of three 'tics' when the 'time base' is set to HIGH (13.7ms), will last 82.2 milliseconds. A typedef You will see the data type 'TONE' throughout the Sefx library. TONE is a structure, defined in sefx.h, used for storing frequency/duration pairs. This type is used mainly by the function SndString. The fields are defined as follows: typedef struct{ int freq; /* frequency */ int durtn; /* duration */ }TONE; 5 Control Functions Before sound can be generated, a call to SndOpen must be made to initialize Sefx. SndOpen will also allocate memory for a sound queue. Sounds are then loaded into the sound queue and played in sequence Prior to program's termination, a call to SndClose must be made to undo SndOpen. Failing to call SndClose prior to a program's termination will cause the computer to lock up requiring a reboot. Other control functions are available for manipulating and procuring the status of the sound queue. The sound queue can be flushed at any time with SndFlush. SndTerm terminates the current sound while SndHold will put all sound on hold. The number of bytes currently residing in the sound queue is available through SndLen. 6 ---------------------------------------------------------------- SndOpen ---------------------------------------------------------------- Function Initializes the timer and interrupt handler and allocates memory for the sound queue. Syntax #include "sefx.h" int SndOpen(unsigned Qsize, int tbase); Parameters Qsize - Size of the sound queue in bytes. The number of bytes required for a sound varies depending on the sound. This value will be rounded down so that it is even multiple of 4 bytes. tbase - Time base. This value determines the length of time of one tic and subsequently how often the frequency can be changed. Possibilities are: LOW (3) - 54.9 milliseconds MED (2) - 27.5 milliseconds HIGH (1) - 13.7 milliseconds ULTRA (0) - 6.9 milliseconds Remarks SndOpen initializes the timer chip, installs the timer interrupt handler, allocates memory for the sound queue and sets the time base. The time base determines how long one tic will be. Since a new tone can be loaded as often as once per tic, this value also determines how often the frequency can be changed. After a call to SndOpen, a subsequent call to SndClose must be made prior to the program's termination. Return value SndOpen returns a zero if no errors occur, or non zero on an error. Constants are defined in sefx.h as follows: NOERR (0) - no errors OPENED (1) - Sefx already opened MALLOC_ERR (4) - queue allocation error 7 See also SndClose SndTbase Example Initialize Sefx, allocate a 1023 byte sound queue and set the time base to MEDium resolution. #define QSIZE 1024 { int rv; rv = SndOpen(QSIZE, MED); if(rv) { ... error handler } ---------------------------------------------------------------- SndClose ---------------------------------------------------------------- Function Restores the timer and timer interrupt, and releases the sound queue from memory. Syntax #include "sefx.h" void SndClose(void); Remarks SndClose restores the timer interrupt vector and the timer chip to normal, and releases the memory allocated for the sound queue. A call to SndClose is required prior to the program's termination. See also SndOpen 8 Example Restore the interrupt vector and free the sound queue prior to termination { ... closing code SndClose(); } ---------------------------------------------------------------- SndLen ---------------------------------------------------------------- Function Determines how many bytes are currently occupying the sound queue. Syntax #include "sefx.h" unsigned SndLen(void); Remarks SndLen determines how many bytes are currently occupying the sound queue. The value is a direct representation of how full the sound queue actually is and does not necessarily represent how much time is left in the queue. Return value SndLen returns the number of bytes currently residing in the sound queue. See also SndFlush SndHold SndTerm 9 Example Check if there is room for 10 more bytes in the sound queue. #define THRESH 512 #define SndThresh() (SndLen() < THRESH) { if(SndThresh()) { ...load more sound } } ---------------------------------------------------------------- SndTbase ---------------------------------------------------------------- Function Sets the time base. Syntax #include "sefx.h" int SndTbase(int tbase); Parameters tbase - Time base. This value determines the length of time of one tic and subsequently how often the frequency can be changed. Possibilities are: LOW (3) - 54.9 milliseconds MED (2) - 27.5 milliseconds HIGH (1) - 13.7 milliseconds ULTRA (0) - 6.9 milliseconds Remarks SndRes sets the time base. This value determines the length of time of one tic, the basic unit of time used by Sefx. Since a new tone can be loaded as often as once per tic, the time base determines how often the frequency can be changed. Return value SndTbase returns the previous time base. 10 See also SndOpen Example Set the time base to 6.9 milliseconds per tic, later restoring the original time base. { int org_tb; org_tb = SndTbase(ULTRA); ... short tones } { ... later SndTbase(org_tb); } ---------------------------------------------------------------- SndFlush ---------------------------------------------------------------- Function Flushes all sound. Syntax #include "sefx.h" void SndFlush(void); Remarks SndFlush flushes the sound queue, deleting all pending and current sounds. It also terminates the current tone. See also SndLen SndTerm SndHold 11 Example Play a song after displaying the opening screen until the user hits a key. { ...display opening screen SndString(song, 100, 0); getch(); SndFlush(); ...continue } ---------------------------------------------------------------- SndHold ---------------------------------------------------------------- Function Puts all sound on hold or releases from hold. Syntax #include "sefx.h" int SndHold(int on_off); Parameters on_off - hold on/off switch. Possibilities are ON (1) - put on hold OFF (0) - release from hold Remarks SndHold puts all sound on hold or releases it from a previous hold condition. When a hold is set, the current tone as well as the sound queue is immediately frozen until it is subsequently released from hold. When a hold condition is released, the sounds will resume where it left off. Return value SndHold returns the previous hold condition 12 See also SndFlush SndTerm Example Make sure the sound is on hold temporarily and then restore it to it's previous condition { int prev_hold; prev_hold = SndHold(ON); ... guaranteed quiet time SndHold(prev_hold); } ---------------------------------------------------------------- SndTerm ---------------------------------------------------------------- Function Terminates the current sound. Syntax #include "sefx.h" void SndTerm(void); Remarks SndTerm terminates the current sound. The sound may be a single tone or many tones. In either case all the tones that make up the sound are terminated. See also SndFlush SndHold Example Terminate the alarm when the user responds #define CONTINUOUS 0 #define Alarm() SndTrill(1400, 600, 8, 8, CONTINUOUS) { Alarm(); ... wait for response SndTerm(); } 13 Sound Generation Sound generation functions load sounds into the sound queue to be played in sequence. Most of the sound generation functions allow the sound to be repeated a specified number of times or continuously. A sounds consisting of a single tone is loaded with SndTone while a sound consisting of a string of tones can be loaded with SndString. Sefx provides sound generation functions for the more common types of sounds. This includes trills, pulses and slides created by the functions SndTrill, SndPulse and SndSlide respectively. These basic sounds can create a multitude of sounds themselves and in addition can be used with other sound generation functions to create more complex combinations. 14 ---------------------------------------------------------------- SndTone ---------------------------------------------------------------- Function Loads a single tone into the sound queue. Syntax #include "sefx.h" void SndTone(int freq, int durtn); Parameters freq - frequency of the tone in hertz. durtn - number of tic the tone will last. Remarks SndTone loads single tone of the specified frequency and duration into the sound queue. Specifying a duration of 0 causes the tone to be played continuously. Specifying a frequency of 0 will generate a pause. The single tone is considered to be one sound. See also SndString SndPause SndTbase SndMs Example Make a two second beep at 2000 hertz. { int second; ... made an error second = SndMs(1000); SndTone(2000, 2*second); } 15 ---------------------------------------------------------------- SndPause ---------------------------------------------------------------- Function Loads a pause into the sound queue. Syntax #include "sefx.h" void SndPause(int durtn); Parameters durtn - number of tics the tone will last Remarks SndPause loads a pause (no sound) of the specified duration into the sound queue. The pause is considered to be one sound. SndPause is a function macro defined as SndTone(0, durtn). See also SndTone SndTbase SndMs Example Insert a three beat pause between two notes #define A 440 #define B 494 { int beat; beat = SndMs(500); SndTone(A, 3*beat); SndPause(3*beat); SndTone(B, 3*beat); } 16 ---------------------------------------------------------------- SndString ---------------------------------------------------------------- Function Loads a string of tones into the sound queue. Syntax #include "sefx.h" void SndString(const TONE *str, int count, unsigned reps); Parameters str - pointer to an array of type TONE were the string of tones are stored. count - number of tones in the array. reps - number of times to repeat the string of tones. Remarks SndString loads an string of tones, stored in an array of type TONE, into the sound queue. The string of tone will be repeated as specified. Specifying a repetition of 0 will cause the string to be repeated continuously. The string of tones is considered to be one sound. See also SndTone SndTbase SndMs SndPause Example Play the scale of notes one time. #define C 262 #define D 294 #define E 330 #define F 349 #define G 392 #define A 440 #define B 494 { TONE scale[7] = { {C,3},{D,3},{E,3},{F,3}, {G,3},{A,3},{B,3} }; SndString(scale, 7, 1); } 17 ---------------------------------------------------------------- SndTrill ---------------------------------------------------------------- Function Loads a trill sound into the sound queue. Syntax #include "sefx.h" void SndTrill(int freq1, int freq2, int durtn1, int durtn2, int reps); Parameters freq1 - frequency of the first tone in hertz. freq2 - frequency of the second tone in hertz. durtn1 - number of tics the first tone will last. durtn2 - number of tics the second tone will last. reps - number of times to repeat the trill sound. Remarks SndTrill loads a trill sound into the sound queue. The trill is repeated as specified. Specifying a repetition of 0 will cause the trill to be repeated continuously. A trill sound is sometimes referred to as a flip-flop sound. See also SndSlide SndPulse SndMs SndTbase Example Make a telephone ring five times. { int i = 5; while(i--) { SndTrill(1400, 600, 1, 1, 10); SndPause(22); } } 18 ---------------------------------------------------------------- SndSlide ---------------------------------------------------------------- Function Loads sliding tones into the sound queue. Syntax #include "sefx.h" void SndSlide(int start, signed dfreq, int durtn, int reps); Parameters start - frequency of the starting tone in hertz. dfreq - change (delta) in frequency per tic. durtn - number of tic the slide will last. reps - number of times to repeat the slide. Remarks SndSlide loads sliding tones into the sound queue. The frequency is increased (positive 'dfreq') or decreased (negative 'dfreq') on each tic by the specified delta frequency. The sliding tone will last the specified duration and will be repeated as specified. To calculate the frequency of the ending tone in the slide use: end = start + (durtn - 1) * dfreq. Hint: shorter (faster) time bases generate a smoother sounding slide while longer (slower) time bases generate a more course sounding slide. Both cases can be useful for creating the desired effect. See also SndTrill SndPulse SndMs SndTbase Example Play a sliding tone from 2000 hertz to 992 hertz { SndSlide(2000, -28, 37); } 19 ---------------------------------------------------------------- SndPulse ---------------------------------------------------------------- Function Loads a pulsing sound into the sound queue. Syntax #include "sefx.h" void SndPulse(int freq, int durtn, int pdurtn, int reps); Parameters freq - frequency of the tone in hertz. durtn - number of tics the tone will last. pdurtn - number of tics the pause will last. reps - number of times to repeat the pulse. Remarks SndPulse loads a tone of the specified frequency and duration, followed by a pause of the specified duration The sound is repeated as specified. Specifying a repetition of 0 will cause the pulse to repeat continuously. SndPulse is a function macro defined as: SndTrill(freq, 0, durtn, pdurtn, reps); See also SndTrill SndSlide SndMs SndTbase Example Make a wrist watch alarm. (Time base = LOW/54.9) { int i = 3; while(i--) { SndPulse(4250, 2, 1, 3); SndPause(9); } } 20 ---------------------------------------------------------------- SndMs ---------------------------------------------------------------- Function Converts milliseconds to tics. Syntax #include "sefx.h" int SndMs(unsigned ms); Parameters ms - number of milliseconds to convert to tics Remarks SndMs converts a value in milliseconds to the equivalent number of tics, rounding off to the nearest tic. SndMs takes into account the current time base and adjusts the resulting number of tics accordingly. The number of tics will always be at least one unless 0 milliseconds is specified. Shorter (faster) time bases result in a more precise conversion than longer (slower) time bases. In most applications this is an insignificant limitation. In any case the value will never be off more that the length of time of one tic. Return value SndMs returns the number of tics that is approximately equal to the specified number of milliseconds. See also SndTbase Example Make a one second tone at 100 hertz { int second; second = SndMs(1000); SndTone(100, second); } 21 Appendix A Things to look out for. ù Sefx takes over interrupt 8 and may change the system clock rate. If the clock rate is changed, Sefx arbitrates the timer chain in order that it's rate remains the same. If a program written with Sefx needs to chain into interrupt 8 it should do so prior to the calling SndOpen. ù The functions SndOpen and SndClose make calls to the C functions malloc and free respectively. ù In the small and medium memory models, the near heap where the sound queue is allocated, is limited. The data segment (globals etc.) + the stack + allocated memory (sound queue) must not exceed 64K bytes. If an extremely large sound queue is required the compact or large model, where the sound queue can be as large as 65532 bytes, should be used. 22 Appendix B Musical notes. This appendix provides information about frequencies of musical notes and octave shifting. The Equal Tempered Chromatic Scale (rounded to integer) note|freq | note|freq | note|freq | note|freq -------------|-------------|-------------|------------- C0 16 | C2 65 | C4 262 | C6 1047 C#0 17 | C#2 69 | C#4 277 | C#6 1109 D0 18 | D2 73 | D4 294 | D6 1175 D#0 19 | D#2 78 | D#4 311 | D#6 1245 E0 21 | E2 82 | E4 330 | E6 1319 F0 22 | F2 87 | F4 349 | F6 1397 F#0 23 | F#2 93 | F#4 370 | F#6 1480 G0 25 | G2 98 | G4 392 | G6 1568 G#0 26 | G#2 104 | G#4 415 | G#6 1661 A0 28 | A2 110 | A4 440 | A6 1760 A#0 29 | A#2 117 | A#4 466 | A#6 1865 B0 31 | B2 123 | B4 494 | B6 1976 | | | C1 33 | C3 131 | C5 523 | C7 2093 C#1 35 | C#3 139 | C#5 554 | C#7 2217 D1 37 | D3 147 | D5 587 | D7 2349 D#1 39 | D#3 156 | D#5 622 | D#7 2489 E1 41 | E3 165 | E5 659 | E7 2637 F1 44 | F3 175 | F5 698 | F7 2794 F#1 46 | F#3 185 | F#5 740 | F#7 2960 G1 49 | G3 196 | G5 784 | G7 3136 G#1 52 | G#3 208 | G#5 831 | G#7 3322 A1 55 | A3 220 | A5 880 | A7 3520 A#1 58 | A#3 233 | A#5 932 | A#7 3729 B1 62 | B3 247 | B5 988 | B7 3951 | C8 4186 Since the frequencies of the octaves increase as a factor of two, musical notes of the other octaves are easily accomplished by multiplying or dividing by factors of two, or more efficiently by shifting left or right. For example to obtain the frequency of A5, the value of A4 (440) is shifted left once (multiplied by two). To obtain the frequency of A2, shift A4 right twice (divide by four). Examples: A5 = A4 << 1 A2 = A4 >> 2 Note: It is better to shift from a higher octave to a lower octave since the percent of rounding error, when rounding to an integer, is smaller with the larger values. Appendix C 23 Appendix C Sound queue usage Some of the sound generation functions load instructional information as well as frequency and duration information. This added information allows Sefx to conserve memory. When the sound is initially loaded by the sound generation function, it will occupy an 'initial' number of bytes in the sound queue. When the next sound is fetched from the sound queue, the instructional information is evaluated and then discarded. The remaining bytes will continue to occupy the sound queue until the sound is terminated. This is referred to in the table below as 'residual'. Initial Residual --------- ---------- SndTone 4 4 SndPause 4 4 SndString 8 + 4 * len 4 * len SndTrill 16 8 SndSlide 8 + 4 * durtn 4 * durtn SndPulse 16 8 24 Appendix D Sefx v1.0 Registration Form Name: ______________________________________________________ Company: ___________________________________________________ Address: ___________________________________________________ City: ____________________________ State: _________________ Zip code: _________________ Phone # : _____________________ CompuServe # : _____________________________________________ How did you acquire Sefx ? _________________________________ ____________________________________________________________ What functions do you find most useful ?____________________ ____________________________________________________________ What functions do you find least useful ?___________________ ____________________________________________________________ What functions, not in Sefx, would you like to see ?________ ____________________________________________________________ What other types of libraries would you find useful ?_______ __ Serial Communications __ Expanded Memory __ IEEE/GPIB __ Game Port Others: ______________________________________ registration $ 25.00 California residents add sales tax ( 8.25% ) $________ shipping inside continental U.S. ( $ 2.00 ) shipping outside continental U.S. ( $ 5.00 ) $________ Total: $________ All Payments Must be in U.S. Dollars Make check or money order payable to: Bri Productions P.O. Box 7121 Fremont, CA 94537-7121 25