| 1 | 'Subj: Re:AdamS60982
|
|---|
| 2 | 'Date: 94-04-17 20:38:07 EDT
|
|---|
| 3 | 'From: AdamS60982
|
|---|
| 4 |
|
|---|
| 5 | 'I couldn't really recommend any SB books since I don't have any. :)
|
|---|
| 6 | 'About the FM, the following example is the best I could find that uses the
|
|---|
| 7 | 'information found in the SB
|
|---|
| 8 | ' SBSOUND.BAS by Brett Levin 1992
|
|---|
| 9 | '
|
|---|
| 10 | ' These routines were made entirely from a pretty detailed(techie, but
|
|---|
| 11 |
|
|---|
| 12 | 'not that I mind <G>) text file on programming the FM ports on the AdLib/SB.
|
|---|
| 13 |
|
|---|
| 14 | ' You are free to use this in any program what so ever, as long as you
|
|---|
| 15 |
|
|---|
| 16 | 'give credit where credit is due.. (stole that line from Rich!) :)
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 | DEFINT A-Z
|
|---|
| 20 | DECLARE FUNCTION DetectCard% ()
|
|---|
| 21 | DECLARE SUB SBInit ()
|
|---|
| 22 | DECLARE SUB WriteReg (Reg%, Value%)
|
|---|
| 23 | DECLARE SUB SBPlay (note%)
|
|---|
| 24 |
|
|---|
| 25 | CONST false = 0, true = NOT false
|
|---|
| 26 |
|
|---|
| 27 | SCREEN 0: CLS
|
|---|
| 28 |
|
|---|
| 29 | IF DetectCard = true THEN
|
|---|
| 30 | PRINT "AdLib-compatible sound card detected."
|
|---|
| 31 | ELSE
|
|---|
| 32 | PRINT "Unable to find/detect sound card."
|
|---|
| 33 | BEEP
|
|---|
| 34 | SYSTEM
|
|---|
| 35 | END IF
|
|---|
| 36 | PRINT " Initalizing...";
|
|---|
| 37 |
|
|---|
| 38 | SBInit
|
|---|
| 39 |
|
|---|
| 40 | PRINT " Done."
|
|---|
| 41 |
|
|---|
| 42 | FOR nt = 0 TO 255
|
|---|
| 43 | SBPlay nt
|
|---|
| 44 | NEXT nt
|
|---|
| 45 |
|
|---|
| 46 | PRINT
|
|---|
| 47 | PRINT " These routines only support one channel/voice of the FM chip, but"
|
|---|
| 48 | PRINT "eventually I may fix them so you can have a bunch o'instruments on"
|
|---|
| 49 | PRINT "at once. I'd also like to write a replacement for SBFMDRV.COM, but"
|
|---|
| 50 | PRINT "that's far off, and probably not in QB anyway. This is too fast"
|
|---|
| 51 | PRINT "compiled, so if you are going to use it in anything, add a delay."
|
|---|
| 52 | PRINT " Enjoy! -Brett 11 / 12 / 92"
|
|---|
| 53 | PRINT
|
|---|
| 54 |
|
|---|
| 55 | FOR nt = 255 TO 0 STEP -1
|
|---|
| 56 | SBPlay nt
|
|---|
| 57 | NEXT nt
|
|---|
| 58 |
|
|---|
| 59 | PRINT "[Press any key to end]"
|
|---|
| 60 | SLEEP
|
|---|
| 61 |
|
|---|
| 62 | CALL WriteReg(&HB0, &H0) 'Makes sure no extra sound is left playing
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 | FUNCTION DetectCard%
|
|---|
| 66 |
|
|---|
| 67 | ' Purpose: Detects an AdLib-compatible card.
|
|---|
| 68 | ' Returns -1 (true) if detected and 0 (false) if not.
|
|---|
| 69 | ' Variables: Nope
|
|---|
| 70 |
|
|---|
| 71 | CALL WriteReg(&H4, &H60)
|
|---|
| 72 | CALL WriteReg(&H4, &H80)
|
|---|
| 73 | B = INP(&H388)
|
|---|
| 74 | CALL WriteReg(&H2, &HFF)
|
|---|
| 75 | CALL WriteReg(&H4, &H21)
|
|---|
| 76 | FOR x = 0 TO 130
|
|---|
| 77 | a = INP(&H388)
|
|---|
| 78 | NEXT x
|
|---|
| 79 | C = INP(&H388)
|
|---|
| 80 | CALL WriteReg(&H4, &H60)
|
|---|
| 81 | CALL WriteReg(&H4, &H80)
|
|---|
| 82 | Success = 0
|
|---|
| 83 | IF (B AND &HE0) = &H0 THEN
|
|---|
| 84 | IF (C AND &HE0) = &HC0 THEN
|
|---|
| 85 | Success = -1
|
|---|
| 86 | END IF
|
|---|
| 87 | END IF
|
|---|
| 88 | DetectCard% = Success
|
|---|
| 89 | END FUNCTION
|
|---|
| 90 |
|
|---|
| 91 | SUB SBInit
|
|---|
| 92 | ' Initialize the sound card
|
|---|
| 93 |
|
|---|
| 94 | '(This is the "quick-and-dirty" method; what it's doing is zeroing out
|
|---|
| 95 |
|
|---|
| 96 | ' all of the card's registers. I haven't had any problems with this.)
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
|
|---|
| 100 | FOR q = 1 TO &HF5
|
|---|
| 101 | CALL WriteReg(q, 0)
|
|---|
| 102 | NEXT q
|
|---|
| 103 |
|
|---|
| 104 | END SUB
|
|---|
| 105 |
|
|---|
| 106 | SUB SBPlay (freq%)
|
|---|
| 107 | ' Purpose: Plays a note
|
|---|
| 108 | ' Variables: freq% - Frequency (00-FF hex)
|
|---|
| 109 | ' duration% - Duration (n seconds) (not used)
|
|---|
| 110 | ' I'm still working on this part, it may be ugly, but it works <g>.
|
|---|
| 111 |
|
|---|
| 112 | ' The first group of WriteRegs is the modulator, the second is the
|
|---|
| 113 |
|
|---|
| 114 | ' carrier.
|
|---|
| 115 | ' If you just want to know how to create your own instrument, play around
|
|---|
| 116 |
|
|---|
| 117 | ' with the second values in the first four calls to WriteReg in each group.
|
|---|
| 118 |
|
|---|
| 119 | ' :-) Have fun! - Brett
|
|---|
| 120 |
|
|---|
| 121 | CALL WriteReg(&H20, &H7) ' Set modulator's multiple to F
|
|---|
| 122 | CALL WriteReg(&H40, &HF) ' Set modulator's level to 40 dB
|
|---|
| 123 | CALL WriteReg(&H60, &HF0) ' Modulator attack: quick, decay: long
|
|---|
| 124 |
|
|---|
| 125 | CALL WriteReg(&H80, &HF0) ' Modulator sustain: medium, release: medium
|
|---|
| 126 | CALL WriteReg(&HA0, freq%)
|
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 | CALL WriteReg(&H23, &HF) ' Set carrier's multiple to 0
|
|---|
| 130 | CALL WriteReg(&H43, &H0) ' Set carrier's level to 0 dB
|
|---|
| 131 | CALL WriteReg(&H63, &HF0) ' Carrier attack: quick, decay: long
|
|---|
| 132 |
|
|---|
| 133 | CALL WriteReg(&H83, &HFF) ' Carrier sustain: quick, release: quick
|
|---|
| 134 | CALL WriteReg(&HB0, &H20) ' Octave
|
|---|
| 135 |
|
|---|
| 136 | CALL WriteReg(&HE0, &H0) ' Waveform argument for Tom..
|
|---|
| 137 | ' &H00 is the default, but I felt like
|
|---|
| 138 | ' dropping it in for you.. :)
|
|---|
| 139 |
|
|---|
| 140 | ' I originally had an extra argument, duration!, but for some reason
|
|---|
| 141 | ' I wanted to do the timing outside of this sub.. You can change it back
|
|---|
| 142 |
|
|---|
| 143 | ' if needs require..
|
|---|
| 144 |
|
|---|
| 145 | 'TimeUp! = TIMER + duation!
|
|---|
| 146 | 'WHILE TimeUp! > TIMER: WEND ' Worst you can be off is .182 of a second
|
|---|
| 147 |
|
|---|
| 148 | END SUB
|
|---|
| 149 |
|
|---|
| 150 | SUB WriteReg (Reg%, Value%)
|
|---|
| 151 | ' Purpose: Writes to any of the SB/AdLib's registers
|
|---|
| 152 | ' Variables: Reg%: Register number,
|
|---|
| 153 | ' Value%: Value to insert in register
|
|---|
| 154 | ' (Note: The registers are from 00-F5 (hex))
|
|---|
| 155 | OUT &H388, Reg '388h = address/status port, 389h = dataport
|
|---|
| 156 | FOR x = 0 TO 5 ' This tells the SB what register we want to write to
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 | a = INP(&H388) ' After we write to the address port we must wait 3.3ms
|
|---|
| 160 |
|
|---|
| 161 | NEXT x
|
|---|
| 162 |
|
|---|
| 163 | OUT &H389, Value ' Send the value for the register to 389h
|
|---|
| 164 | FOR x = 0 TO 34 ' Here we must also wait, this time 23ms
|
|---|
| 165 | a = INP(&H388)
|
|---|
| 166 | NEXT x
|
|---|
| 167 | END SUB
|
|---|
| 168 |
|
|---|