VirtualBox

Ticket #17867: sbsound.c

File sbsound.c, 6.7 KB (added by MarchHare, 6 years ago)
Line 
1#include "sbsound.h"
2
3/*
4Subj: Re:AdamS60982
5Date: 94-04-17 20:38:07 EDT
6From: AdamS60982
7
8I couldn//t really recommend any SB books since I don//t have any. :)
9About the FM, the following example is the best I could find that uses the
10information found in the SB
11 SBSOUND.BAS by Brett Levin 1992
12
13 These routines were made entirely from a pretty detailed(techie, but
14
15not that I mind <G>) text file on programming the FM ports on the AdLib/SB.
16
17 You are free to use this in any program what so ever, as long as you
18
19give credit where credit is due.. (stole that line from Rich!) :)
20*/
21
22 //DEFINT A-Z
23int DetectCard(void); //DECLARE FUNCTION DetectCard% ()
24void SBInit(void); //DECLARE SUB SBInit ()
25void WriteReg(short Reg, short Value); //DECLARE SUB WriteReg (Reg%, Value%)
26void SBPlay(short freq); //DECLARE SUB SBPlay (freq%)
27uint8_t inb(uint16_t port);
28void outb(uint16_t port, uint8_t val);
29extern void puts(char * str);
30
31//CONST false = 0, true = NOT false
32
33//SCREEN 0: CLS
34
35void SoundTest(void){
36 /*
37 IF DetectCard = true THEN
38 PRINT "AdLib-compatible sound card detected."
39 ELSE
40 PRINT "Unable to find/detect sound card."
41 BEEP
42 SYSTEM
43 END IF
44 PRINT " Initalizing..."
45 */
46
47/*
48 if (DetectCard()){
49 puts("AdLib-compatible sound card detected.\r\n\0");
50 }
51 else
52 {
53 puts("Unable to find/detect sound card.\r\n\0");
54 //beep();
55 return;
56 }
57
58
59 puts(" Initalizing...\r\n\0");
60 SBInit();
61 puts(" Done.\r\n\0");
62*/
63
64 for(int nt = 0; nt<256; ++nt){ //FOR nt = 0 TO 255
65 SBPlay(nt);
66 } //NEXT nt
67
68 puts("\r\nThese routines only support one channel/voice of the FM chip, but\r\n\0");
69 puts("eventually I may fix them so you can have a bunch o'instruments on\r\n\0");
70 puts("at once. I'd also like to write a replacement for SBFMDRV.COM, but\r\n\0");
71 puts("that's far off, and probably not in QB anyway. This is too fast\r\n\0");
72 puts("compiled, so if you are going to use it in anything, add a delay.\r\n\0");
73 puts(" Enjoy! -Brett 11 / 12 / 92\r\n\0");
74
75
76 for(int nt = 255; nt>-1; --nt){ //FOR nt = 255 TO 0 STEP -1
77 SBPlay(nt);
78 } //NEXT nt
79
80// puts("[Press any key to end]\r\n\0");
81 //SLEEP
82
83 WriteReg(0xB0, 0x0); //Makes sure no extra sound is left playing
84
85 return;
86}
87
88
89int DetectCard(void){
90
91// Purpose: Detects an AdLib-compatible card.
92// Returns -1 (true) if detected and 0 (false) if not.
93// Variables: Nope
94
95 WriteReg(0x4, 0x60);
96 WriteReg(0x4, 0x80);
97
98 int B = inb(0x388);
99
100 WriteReg(0x2, 0xFF);
101 WriteReg(0x4, 0x21);
102
103 for (int x = 0; x <= 130; ++x){ // FOR x = 0 TO 130
104 int a = inb(0x388);
105 } // NEXT x
106
107 int C = inb(0x388);
108
109 WriteReg(0x4, 0x60);
110 WriteReg(0x4, 0x80);
111
112 if ((B & 0xE0) == 0x00) {
113 if ((C & 0xE0) == 0xC0) {
114 return -1;
115 }
116 }
117
118 return 0;
119}
120
121void SBInit(void){
122// Initialize the sound card
123//(This is the "quick-and-dirty" method; what it//s doing is zeroing out
124// all of the card//s registers. I haven//t had any problems with this.)
125
126 for(int q = 0; q < 0xF6; ++q){ //FOR q = 1 TO &HF5
127 WriteReg(q, 0);
128 } //NEXT q
129
130 return;
131}
132
133void WriteReg(short Reg, short Value){
134// Purpose: Writes to any of the SB/AdLib//s registers
135// Variables: Reg%: Register number,
136// Value%: Value to insert in register
137// (Note: The registers are from 00-F5 (hex))
138
139 outb(0x388, Reg); //388h = address/status port, 389h = dataport
140 for(int x = 0; x <= 5; ++x){ // This tells the SB what register we want to write to
141 inb(0x388); // After we write to the address port we must wait 3.3ms
142 }
143
144 outb(0x389, Value); // Send the value for the register to 389h
145 for(int x = 0; x <= 34; ++x){ // Here we must also wait, this time 23ms
146 inb(0x388);
147 }
148
149 return;
150}
151
152void SBPlay(short freq){
153// Purpose: Plays a note
154// Variables: freq% - Frequency (00-FF hex)
155// duration% - Duration (n seconds) (not used)
156// I//m still working on this part, it may be ugly, but it works <g>.
157
158// The first group of WriteRegs is the modulator, the second is the
159
160// carrier.
161// If you just want to know how to create your own instrument, play around
162
163// with the second values in the first four calls to WriteReg in each group.
164
165// :-) Have fun! - Brett
166
167 WriteReg(0x20, 0x7); // Set modulator's multiple to F
168 WriteReg(0x40, 0xF); // Set modulator's level to 40 dB
169 WriteReg(0x60, 0xF0); // Modulator attack: quick, decay: long
170
171 WriteReg(0x80, 0xF0); // Modulator sustain: medium, release: medium
172 WriteReg(0xA0, freq);
173
174
175 WriteReg(0x23, 0xF); // Set carrier's multiple to 0
176 WriteReg(0x43, 0x0); // Set carrier's level to 0 dB
177 WriteReg(0x63, 0xF0); // Carrier attack: quick, decay: long
178
179 WriteReg(0x83, 0xFF); // Carrier sustain: quick, release: quick
180 WriteReg(0xB0, 0x20); // Octave
181
182 WriteReg(0xE0, 0x0); // Waveform argument for Tom..
183 // &H00 is the default, but I felt like
184 // dropping it in for you.. :)
185
186// I originally had an extra argument, duration!, but for some reason
187// I wanted to do the timing outside of this sub.. You can change it back
188
189// if needs require..
190
191//TimeUp! = TIMER + duation!
192//WHILE TimeUp! > TIMER: WEND // Worst you can be off is .182 of a second
193
194 return;
195
196}
197
198uint8_t inb(uint16_t port)
199{
200 uint8_t ret;
201 __asm__ volatile ( "inb %1, %0"
202 : "=a"(ret)
203 : "Nd"(port) );
204 return ret;
205}
206
207void outb(uint16_t port, uint8_t val)
208{
209 __asm__ volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
210 /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
211 * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
212 * The outb %al, %dx encoding is the only option for all other cases.
213 * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
214}

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy