]> 4ch.mooo.com Git - 16.git/blob - 16/16/opl2.c
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / 16 / 16 / opl2.c
1 /* C Source File: ADLIB *****************************************************\r
2 \r
3 Author:            Kevin A. Lee\r
4 \r
5 Last Amended:      27th March, 1993\r
6 \r
7 Description:        Low-level interface to the Adlib (or compatible)\r
8 FM sound card. All information gleaned from\r
9 Jeffrey S. Lee's "Programming the Adlib/Sound\r
10 Blaster FM Music Chips". See Lee's document for\r
11 further information.\r
12 Compiled succesfully under Turbo C, Borland C++,\r
13 and Microsoft Quick C (all latest versions).\r
14 \r
15 ****************************************************************************/\r
16 #include "src\lib\opl2.h"\r
17
18 //sound てすと
19 int sq = 0;
20 \r
21 /* Function: WriteFM ********************************************************\r
22 *\r
23 *     Parameters:        reg - which FM register to write to.\r
24 *                         value - value to write.\r
25 *\r
26 *     Description:        writes a value to the specified register and\r
27 *                         waits for the "official" recommended periods.\r
28 *\r
29 */\r
30 void WriteFM(int reg, int value){\r
31         int i;\r
32 \r
33         outp(ADLIB_FM_ADDRESS, (byte)reg);                              /* set up the register  */\r
34         for (i = 0; i < 6; i++) inp(ADLIB_FM_ADDRESS);  /* wait 12 cycles      */\r
35         outp(ADLIB_FM_DATA, (byte)value);                                       /* write out the value */\r
36         for(i = 0; i < 35; i++) inp(ADLIB_FM_ADDRESS);  /* wait 84 cycles      */\r
37 } /* End of WriteFM */\r
38 \r
39 /* Function: ReadFM *********************************************************\r
40 *\r
41 *     Returns:            the value in the status register.\r
42 *\r
43 *     Description:        return a value in the status register.\r
44 *\r
45 */\r
46 int ReadFM(void){\r
47         return(inp(ADLIB_FM_ADDRESS));\r
48 } /* End of ReadFM */\r
49 \r
50 /* Function: AdlibExists ****************************************************\r
51 *\r
52 *     Returns:            1 (true) if an Adlib compatible sound card\r
53 *                         is present, else 0 (false).\r
54 *\r
55 *     Description:        determines whether an Adlib (or compatible)\r
56 *                         sound card is present.\r
57 *\r
58 */\r
59 int AdlibExists(void){\r
60         int stat1, stat2;\r
61 \r
62         WriteFM(0x04, 0x60);            /* reset both timers        */\r
63         WriteFM(0x04, 0x80);            /* enable timer interrupts  */\r
64         stat1 = ReadFM();                       /* read status register     */\r
65         WriteFM(0x02, 0xFF);\r
66         WriteFM(0x04, 0x21);            /* start timer 1            */\r
67 //      wait(80);                               /* could do something useful*/\r
68         stat2 = ReadFM();                       /* read status register     */\r
69         WriteFM(0x04, 0x60);            /* reset both timers        */\r
70         WriteFM(0x04, 0x80);            /* enable timer interrupts  */\r
71 \r
72         if(((stat1 & 0xE0) == 0x00) && ((stat2 & 0xE0) == 0xC0)) return(1);\r
73         return(0);\r
74 } /* End of AdlibExists */\r
75 \r
76 /* Function: FMResest *******************************************************\r
77 *\r
78 *     Description:        quick and dirty sound card reset (zeros all\r
79 *                         registers).\r
80 *\r
81 */\r
82 void FMReset(void/*int percusiveMode*/){\r
83         int i;\r
84 \r
85         /* zero all registers */\r
86         for(i = MIN_REGISTER; i < MAX_REGISTER+1; i++) WriteFM(i, 0);\r
87 \r
88         /* allow FM chips to control the waveform of each operator */\r
89         WriteFM(0x01, 0x20);\r
90 \r
91         /* set rhythm enabled (6 melodic voices, 5 percussive) */\r
92         WriteFM(0xBD, 0x20);\r
93 \r
94         //FMSetPercusiveMode(percusiveMode);\r
95 } /* End of FMReset */\r
96 /*\r
97 void FMSetPercusiveMode(int state){\r
98         if(state){\r
99                 WriteFM(0xBD, 0x20);\r
100                 currentBDContents = 0x20;\r
101                 percussiveMode = 1;\r
102                 voiceModulator[7] = 16;\r
103                 voiceModulator[8] = 14;\r
104                 // we have to set the freq of voice 7 & 8 for the white noise gen.\r
105                 // these frequency choices could certainly be better\r
106                 WriteFM(0xa7, 1844 & 0xff);\r
107                 WriteFM(0xb7, 1844 >> 8);\r
108                 WriteFM(0xa8, 3764 & 0xff);\r
109                 WriteFM(0xb8, 3764 >> 8);\r
110         }else{\r
111                 WriteFM(0xBD, 0);\r
112                 percussiveMode = 0;\r
113                 currentBDContents = 0;\r
114                 voiceModulator[7] = 13;\r
115                 voiceModulator[8] = 14;\r
116         }\r
117 }\r
118 */\r
119 /* Function: FMKeyOff *******************************************************\r
120 *\r
121 *     Parameters:        voice - which voice to turn off.\r
122 *\r
123 *     Description:        turns off the specified voice.\r
124 *\r
125 */\r
126 void FMKeyOff(int voice){\r
127         int regNum;\r
128 \r
129         /* turn voice off */\r
130         regNum = 0xB0 + voice % NUMVOICE;\r
131         WriteFM(regNum, 0x0E);\r
132 } /* End of FMKeyOff */\r
133 \r
134 /* Function: FMKeyOn *******************************************************\r
135 *\r
136 *     Parameters:        voice - which voice to turn on.\r
137 *                         freq - its frequency (note).\r
138 *                         octave - its octave.\r
139 *\r
140 *     Description:        turns on a voice of specfied frequency and\r
141 *                         octave.\r
142 *\r
143 */\r
144 void FMKeyOn(int voice, int freq, int octave){\r
145         int regNum, tmp;\r
146 \r
147         regNum = 0xA0 + voice % NUMVOICE;\r
148         WriteFM(regNum, freq & 0xff);\r
149         regNum = 0xB0 + voice % NUMVOICE;\r
150         tmp = (freq >> 8) | (octave << 2) | 0x20;
151         WriteFM(regNum, tmp);\r
152 } /* End of FMKeyOn */\r
153 \r
154 /* Function: FMVoiceVolume **************************************************\r
155 *\r
156 *     Parameters:        voice - which voice to set volume of\r
157 *                         vol - new volume value (experiment).\r
158 *\r
159 *     Description:        sets the volume of a voice to the specified\r
160 *                         value in the range (0-63)?\r
161 *\r
162 */\r
163 void FMVoiceVolume(int voice, int vol){\r
164         int regNum;\r
165 \r
166         regNum = 0x40 + voice % NUMVOICE;\r
167         WriteFM(regNum, vol);\r
168 } /* End of FMVoiceVolume */\r
169 \r
170 /* Function: FMSetVoice *****************************************************\r
171 *\r
172 *     Parameters:        voiceNum - which voice to set.\r
173 *                         ins - instrument to set voice.\r
174 *\r
175 *     Description:        sets the instrument of a voice.\r
176 *\r
177 */\r
178 void FMSetVoice(int voiceNum, FMInstrument *ins){\r
179         int opCellNum, cellOffset;\r
180 \r
181         voiceNum %= NUMVOICE;\r
182         cellOffset = voiceNum % 3 + ((voiceNum / 3) << 3);\r
183 \r
184         /* set sound characteristic */\r
185         opCellNum = 0x20 + (char)cellOffset;\r
186         WriteFM(opCellNum, ins->SoundCharacteristic[0]);\r
187         opCellNum += 3;\r
188         WriteFM(opCellNum, ins->SoundCharacteristic[1]);\r
189 \r
190         /* set level/output */\r
191         opCellNum = 0x40 + (char)cellOffset;\r
192         WriteFM(opCellNum, ins->Level[0]);\r
193         opCellNum += 3;\r
194         WriteFM(opCellNum, ins->Level[1]);\r
195 \r
196         /* set Attack/Decay */\r
197         opCellNum = 0x60 + (char)cellOffset;\r
198         WriteFM(opCellNum, ins->AttackDecay[0]);\r
199         opCellNum += 3;\r
200         WriteFM(opCellNum, ins->AttackDecay[1]);\r
201 \r
202         /* set Sustain/Release */\r
203         opCellNum = 0x80 + (char)cellOffset;\r
204         WriteFM(opCellNum, ins->SustainRelease[0]);\r
205         opCellNum += 3;\r
206         WriteFM(opCellNum, ins->SustainRelease[1]);\r
207 \r
208         /* set Wave Select */\r
209         opCellNum = 0xE0 + (char)cellOffset;\r
210         WriteFM(opCellNum, ins->WaveSelect[0]);\r
211         opCellNum += 3;\r
212         WriteFM(opCellNum, ins->WaveSelect[1]);\r
213 \r
214         /* set Feedback/Selectivity */\r
215         opCellNum = (byte)0xC0 + (byte)voiceNum;\r
216         WriteFM(opCellNum, ins->Feedback);\r
217 } /* End of FMSetVoice */\r
218 \r
219 /* Function: LoadSBI ********************************************************\r
220 *\r
221 *     Parameters:        fileName - name of .SBI file.\r
222 *                         ins - variable to place data in.\r
223 *\r
224 *     Description:        loads a .SBI into the instrument structure.\r
225 *\r
226 */\r
227 //int LoadSBI(char fileName[], FMInstrument *ins){\r
228 //  int i;\r
229 //  FILE *fp;\r
230 //  size_t structSize = sizeof(FMInstrument);\r
231 //\r
232 //  if ((fp = fopen(fileName, "rb")) == NULL) return (0);\r
233 //\r
234 //  /* skip the header - or do we? */\r
235 //  for (i = 0; i < 36; i++) fgetc(fp);\r
236 //\r
237 //  /* read the data */\r
238 //  fread(ins, structSize, 1, fp);\r
239 //\r
240 //  fclose(fp);\r
241 //  return (1);\r
242 //} /* End of LoadSBI */\r
243
244 unsigned short Notes[] = {\r
245         19327 ,        /* C b            */\r
246         18242 ,        /* C              */\r
247         17218 ,        /* C #   ( D b )  */\r
248         16252 ,        /* D              */\r
249         15340 ,        /* D #   ( E b )  */\r
250         14479 ,        /* E     ( F b )  */\r
251         13666 ,        /* F     ( E # )  */\r
252         12899 ,        /* F #   ( G b )  */\r
253         12175 ,        /* G              */\r
254         11492 ,        /* G #   ( A b )  */\r
255         10847 ,        /* A              */\r
256         10238 ,        /* A #   ( B b )  */\r
257         9664 ,         /* B     ( C b )  */\r
258         9121 ,         /* B #            */\r
259         0\r
260 };
261 \r
262 /* test of the routines */\r
263 void fmtest(){\r
264         enum SCALE test[] = { D4, E4, F4, G4, A4, B4, C4 };\r
265 //      enum SCALE oct4[] = { 493.88, 466.16, 440, 415.3, 392, 369.99, 349.23, 329.63, 311.13, 293.66, 277.18, 261.63 };\r
266         static FMInstrument testInst =\r
267 {\r
268 0x00, 0x01,     /* modulator frequency multiple... 0x20 */\r
269 0x00, 0x00,     /* modulator frequency level...    0x40 */\r
270 0xF0, 0xF0,     /* modulator attack/decay...       0x60 */\r
271 0x73, 0x73,     /* modulator sustain/release...    0x80 */\r
272 0x03, 0x00,     /* output waveform distortion      0xE0 */\r
273 0x36,                           /* feedback algorithm and strength 0xC0 */\r
274 };\r
275         int i;\r
276         printf("Now testing tune....\n");\r
277 //      printf("just hit any key 7 times.\n");\r
278         FMReset();\r
279         FMSetVoice(0, &testInst);
280         //extra
281 //      WriteFM(0xB0, 0x09);
282 //      WriteFM(0xB3, 0x07);
283         //extra
284         for(i = 0; i < 7; i++){\r
285                 FMKeyOn(0, test[i], 4);
286                 sound(test[i]);\r
287                 wait(20);\r
288 //              getche();
289                 FMKeyOff(0);
290                 nosound();\r
291                 wait(1);\r
292         }\r
293 }
294
295 //sound てすと
296 int soundtest(){
297         enum SCALE test[] = { D4, E4, F4, G4, A4, B4, C4 };\r
298         //FMKeyOn(0, test[sq], 4);
299         if(sq < 7){\r
300                 sq++;\r
301         }else sq = 0;
302         FMKeyOff(0);
303         return sq;
304 }