Contributor: JOHN HOWARD { Two ways to create dial tones: digital sample for each tone, or generate tone with a digital to analog convertor. The MCI mmSystem uses MS Windows 3.1 high resolution timer. The following demonstrate other ways to generate tones: } program PlayTone; { Author: John Howard } uses WinProcs; (* Comments from Don Phillip Gibson, CompuServe [75725,1752] are enclosed in star brackets *) const Magic : integer=376; Tempo : integer = 120; NoteType : integer = 4; (* Magic is used as a multiplier to determine the duration of a note. The Windows API documentation for setVoiceSound indicates that duration should be a straight forward calculation of yea-so-many clock ticks. It just isn't so. Brute force experimentation found 376. It seems to work fine regardless of processor speed or whatever. I've tested on 386/33, 386/16, and 8088/4.7 machines -- they all work. Let me tell you, it was sure fun setting up and running Windows on that 8088/4.7 CGA equipment. The actual tone production routines follow. If you've explored the API music functions at all, you may wonder why I'm using setVoiceSound instead of setVoiceNote. setVoiceNote seems, on the surface, to be the automatic way to write these sorts of things, but it just doesn't work very well. Whole notes and half notes are incorrectly produced, dots are impossible, and the nicety of having legato is gone. setVoiceSound works much better, though it does require that you calculate a duration rather than just specifying tempo and length. Windows wants the fractional and integer portions of the frequency stuffed respectively into the low and high words of a long integer. setVoiceSound doesn't provide for a rest. Instead, I've plugged an impossibly high pitch into the [0] slot of that array. It's presumably playing, but you shouldn't hear it. *) var Pitch : array[0..84] of LongInt; Herz : array[0..11] of Real; Tone : integer; { index } function Duration(Tempo, NoteType : integer) : integer; var Temp : real; begin Temp := 60 / Tempo * Magic * 4 / NoteType; Duration := trunc(Temp); end; BEGIN {main} Pitch[0] := MakeLong(0,20000); Tone := 0; { example tone index } Herz[Tone] := 523.25; { note 'C' white frequency } Pitch[Tone+1] := MakeLong(trunc(frac(Herz[Tone])),trunc(int(Herz[Tone]))); setVoiceSound(1,Pitch[Tone+1],Duration(Tempo,NoteType) * 7 div 8 ); {1. Accept note number} setVoiceSound(1,Pitch[0],Duration(Tempo,NoteType) * 1 div 8 ); {2. Sound off, zero means silence} {3. Translate note into 'frequency'} {4. Setup timer chip} {5. Setup frequency} {6. Sound on} {7. Setup note length delays} (* I don't know why I've got to send one last 'empty' note to the voice queue, but without it, the last real note doesn't get played. That's the purpose of the next statement. *) setVoiceSound(1,0,1); setVoiceThreshold(1,0); StartSound; repeat until GetThresholdStatus = 1; CloseSound; END. {main} 1-800-451-6644 Philips/Signetics BBS Filename: DTMF.ZIP { snippet follows } ; The following code uses both timers in an 80c31 to generate ; DTMF tones, and signalling tones such as BUSY, RING-BACK, etc. ; This file also contains the connections for a very crude 2 bit ; per tone A\D converter wich uses 4 bits of P1 and a low pass filter. ; Compensation for twist isn't included but could be handled by ; playing with the hi and low tone dac values and the summing amp ; input resistors. ; ; If this code is used in any application I only request that ; credit be given to me: ; Bert Rinne ; Advanced Logic Systems Inc. ; 13 Twin Meadows Dr. ; Hudson N.H. 03051 ; (C) 1993 ; *** Another method of tone generation is documented in the ; 'YUCK' Zilog Z8 microcontrollers book circa 1991 using the ; Super8. It is a waveform synthesis model using a 8Khz sampled ; data system with 1 timer and an 8 bit dac. If anyone should ; adapt the technique to the '51/'31 family please post the ; code on this BBS in return for the info. ; ; Bert Rinne 12/93 SIGNAL_LOW equ 021h ;2 bytes for signal fLOW timer SIGNAL_HIGH equ 023h ;2 bytes for signal fHIGH timer fHIGH equ 025h ; frequency high fLOW equ 026h ; frequency low CNT_10mS equ 027h ; decrement 10 millisecond used as a timer ; HARDWARE CONFIGURATION ____/\/\/\___ ;--------, | | ; 8031 | 47k +-----][----| ; P1.0 |-----/\/\/\------, | | ; | 12k +--/\/\/\--, | \ | ; P1.1 |-----/\/\/\------' | | | \ | ; | +---][---+---|- \_|____||___ ; | 47k | | / || ; P1.2 |-----/\/\/\------, | ,--|+ / ; | 12k |--/\/\/\--' | |/ ; P1.3 |-----/\/\/\------' | ;--------' +2.5V ; ; the dac uses 3 bits per channel internal to the mpu and ; counts as follows 000 001 010 011 100 101 110 111 ; using bit 2 as the sign and complementing bits 0 & 1 we ; get 000 001 010 011 111 110 101 100 and ; output 00 01 10 11 11 10 01 00 ; The above was coupled to a 100mw amp and used to dial the phone ; via acoustical coupling (held phone near speaker) with no errors. ; ; Funky DAC courtesy of Don Lancaster's wonderful book - ; The CMOS Cookbook, Howard Sams Inc. ; ; DIALING TONES (dtmf) ; ; 1209 1336 1477 1633 ; ; 697 1 2 3 A ; ; 770 4 5 6 B ; ; 852 7 8 9 C ; ; 941 * 0 # D ; ; Using the formula f = -(((osc/12)/bits-per-cycle)/desired-freq.) ; ; thus at 11.059 MHz clock and 8 bits per cycle: ; ; desired timer value actual freq ; 697 = -165 698.2 ; 770 = -150 768 ; 852 = -135 853.3 ; 941 = -122 944 ; ; 1209 = -95 1212.6 ; 1336 = -86 1339.5 ; 1477 = -78 1476.9 ; 1633 = -71 1622.5 ; Low frequency low byte F697 equ LOW(-165) F770 equ LOW(-150) F852 equ LOW(-135) F941 equ LOW(-122) ; High frequency low byte F1209 equ LOW(-95) F1336 equ LOW(-86) F1477 equ LOW(-78) F1633 equ LOW(-71) ; Tone time on >40 mS Bell spec minimum so we ; Tone time off >40 mS will use 100mS on/70 mS off ; ; SIGNAL TONES ; NOTE *** the signal tone values are adjusted by LOAD_DTMF: ; to compensate for latency time while re-loading the timers. ; The latency time is 2 us. and is critical for ; valid signal tone frequencies. ; ; Low High (Hz) ; Dial tone 350 440 steady tone -13dBm ; ring-back 440 480 2 sec on/ 4 sec off -19dBm ; busy 480 620 .5 sec on/.5 sec off -24dBm ; NOTE: ******* ; Although the following are not implemented, they are valid ; signal tones: ; ; Reorder: 480 620 .25 sec on/.25 sec off -24dBm ; ; Partial dial tone ; 480 steady tone -17dBm ; ; Auto credit call prompting: ; 941 1477 940 mSEC -10dBm/freq. ; followed by 440 350 exponentially decaying from -10dBm ; @ a time constant of 200mSec. ; ; Reference: Mitel Semiconductor Data book circa '86-'87. ; "Credit must be given where due." ; ; Pulse dialing can be accomplished very easily using the timers ; and if you're reading this you can figure it out. ; ; desired timer value actual freq ; 350 -329 350 ; 440 -262 439.7 ; 480 -240 480 ; 620 -186 619 F350 equ -329 F440 equ -262 F480 equ -240 F620 equ -186 TONE_TBL: ; 0 db F941 ;fLOW = 941 db F1336 ;fHIGH = 1336 db 76 ;76 * fLOW intrs = 10mS db 0 ; 1 db F697 ;fLOW = 697 db F1209 ;fHIGH = 1209 db 56 ;56 * fLOW intrs = 10 mS db 0 ; 2 db F697 ;fLOW = 697 db F1336 ;fHIGH = 1336 db 56 db 0 ; 3 db F697 ;fLOW = 697 db F1477 ;fHIGH = 1477 db 56 db 0 ; 4 db F770 ;fLOW = 770 db F1209 ;fHIGH = 1209 db 62 db 0 ; 5 db F770 ;fLOW = 770 db F1336 ;fHIGH = 1336 db 62 db 0 ; 6 db F770 ;fLOW = 770 db F1477 ;fHIGH = 1477 db 62 db 0 ; 7 db F852 ;fLOW = 852 db F1209 ;fHIGH = 1209 db 68 db 0 ; 8 db F852 ;fLOW = 852 (853) db F1336 ;fHIGH = 1336 (1340) db 68 db 0 ; 9 db F852 ;fLOW = 852 (853) db F1477 ;fHIGH = 1477 (1477) db 68 db 0 ; A db F697 ;fLOW = 697 (698) db F1633 ;fHIGH = 1633 (1622) db 56 db 0 ; B db F770 ;fLOW = 770 (768) db F1633 ;fHIGH = 1633 (1622) db 62 db 0 ; C db F852 ;fLOW = 852 (853) db F1633 ;fHIGH = 1633 (1622) db 68 db 0 ; D db F941 ;fLOW = 941 (944) db F1633 ;fHIGH = 1633 (1622) db 76 db 0 ; * db F941 ;fLOW = 941 (944) db F1209 ;fHIGH = 1209 (1213) db 76 db 0 ; # db F941 ;fLOW = 941 (944) db F1477 ;fHIGH = 1477 (1477) db 76 db 0