1 #include "audio.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 #include "audio_sod.h"
7 #include "audio_wl1.h"
8 #include "audio_wl6.h"
9 #include "mame/fmopl.h"
10
11 #define PATH_MAX 4096
12 static int volume = 20;
13 static const int oplChip = 0;
14 #define OPL_CHANNELS 9
15 #define MUSIC_RATE 700
16 #define SOUND_RATE 140 // Also affects PC Speaker sounds
17 #define SOUND_TICKS (MUSIC_RATE / SOUND_RATE)
18 #define SAMPLES_PER_MUSIC_TICK (MUSIC_SAMPLE_RATE / MUSIC_RATE)
19
20 #pragma pack(push, 1)
21 typedef struct
22 {
23 uint8_t mChar, cChar, mScale, cScale, mAttack, cAttack, mSus, cSus, mWave,
24 cWave, nConn,
25
26 // These are only for Muse - these bytes are really unused
27 voice, mode;
28 uint8_t unused[3];
29 } AlInstrument;
30
31 typedef struct
32 {
33 uint32_t length;
34 uint16_t priority;
35 AlInstrument inst;
36 uint8_t block;
37 uint8_t data[1];
38 } AdLibSound;
39 #pragma pack(pop)
40
41 static const AlInstrument ChannelRelease = {
42 0, 0, 0x3F, 0x3F, 0xFF, 0xFF, 0xF, 0xF, 0, 0, 0,
43
44 0, 0, {0, 0, 0}};
45
46 #define alOut(n, b) YM3812Write(oplChip, n, b, &volume)
47
48 // Register addresses
49 // Operator stuff
50 #define alChar 0x20
51 #define alScale 0x40
52 #define alAttack 0x60
53 #define alSus 0x80
54 #define alWave 0xe0
55 // Channel stuff
56 #define alFreqL 0xa0
57 #define alFreqH 0xb0
58 #define alFeedCon 0xc0
59 // Global stuff
60 #define alEffects 0xbd
61
AlSetChanInst(const AlInstrument * inst,unsigned int chan)62 static void AlSetChanInst(const AlInstrument *inst, unsigned int chan)
63 {
64 static const uint8_t chanOps[OPL_CHANNELS] = {0, 1, 2, 8, 9,
65 0xA, 0x10, 0x11, 0x12};
66 uint8_t c, m;
67
68 m = chanOps[chan]; // modulator cell for channel
69 c = m + 3; // carrier cell for channel
70 alOut(m + alChar, inst->mChar);
71 alOut(m + alScale, inst->mScale);
72 alOut(m + alAttack, inst->mAttack);
73 alOut(m + alSus, inst->mSus);
74 alOut(m + alWave, inst->mWave);
75 alOut(c + alChar, inst->cChar);
76 alOut(c + alScale, inst->cScale);
77 alOut(c + alAttack, inst->cAttack);
78 alOut(c + alSus, inst->cSus);
79 alOut(c + alWave, inst->cWave);
80
81 alOut(chan + alFreqL, 0);
82 alOut(chan + alFreqH, 0);
83 alOut(chan + alFeedCon, 0);
84 }
85
CWAudioLoadHead(CWAudioHead * head,const char * path)86 int CWAudioLoadHead(CWAudioHead *head, const char *path)
87 {
88 int err = 0;
89 FILE *f = fopen(path, "rb");
90 if (!f)
91 {
92 err = -1;
93 fprintf(stderr, "Failed to read %s", path);
94 goto bail;
95 }
96 fseek(f, 0, SEEK_END);
97 const long fsize = ftell(f);
98 fseek(f, 0, SEEK_SET);
99 head->nOffsets = fsize / sizeof(uint32_t);
100 head->offsets = malloc(head->nOffsets * sizeof(uint32_t));
101 if (fread(head->offsets, sizeof(uint32_t), head->nOffsets, f) !=
102 head->nOffsets)
103 {
104 err = -1;
105 fprintf(stderr, "Failed to read audio head\n");
106 goto bail;
107 }
108
109 // Init adlib
110 if (YM3812Init(1, 3579545, MUSIC_SAMPLE_RATE))
111 {
112 fprintf(stderr, "Unable to create virtual OPL\n");
113 goto bail;
114 }
115 for (int i = 1; i < 0xf6; i++)
116 {
117 YM3812Write(oplChip, i, 0, &volume);
118 }
119 YM3812Write(oplChip, 1, 0x20, &volume); // Set WSE=1
120
121 bail:
122 if (f)
123 {
124 fclose(f);
125 }
126 return err;
127 }
128
CWAudioHeadFree(CWAudioHead * head)129 void CWAudioHeadFree(CWAudioHead *head)
130 {
131 free(head->offsets);
132 }
133
CWAudioLoadAudioT(CWAudio * audio,const CWMapType type,const char * path)134 int CWAudioLoadAudioT(CWAudio *audio, const CWMapType type, const char *path)
135 {
136 int err = 0;
137 FILE *f = fopen(path, "rb");
138 if (!f)
139 {
140 err = -1;
141 fprintf(stderr, "Failed to read %s", path);
142 goto bail;
143 }
144 const uint32_t len = audio->head.offsets[audio->head.nOffsets - 1];
145 audio->data = malloc(len);
146 if (fread(audio->data, 1, len, f) != len)
147 {
148 err = -1;
149 fprintf(stderr, "Failed to read audio data");
150 goto bail;
151 }
152 switch (type)
153 {
154 case CWMAPTYPE_WL1:
155 CWAudioWL1LoadAudioT(audio);
156 break;
157 case CWMAPTYPE_WL6:
158 CWAudioWL6LoadAudioT(audio);
159 break;
160 case CWMAPTYPE_SOD:
161 CWAudioSODLoadAudioT(audio);
162 break;
163 }
164
165 bail:
166 if (f)
167 {
168 fclose(f);
169 }
170 return err;
171 }
172
CWAudioFree(CWAudio * audio)173 void CWAudioFree(CWAudio *audio)
174 {
175 CWAudioHeadFree(&audio->head);
176 YM3812Shutdown();
177 free(audio->data);
178 }
179
CWAudioGetAdlibSoundRaw(const CWAudio * audio,const int i,const char ** data,size_t * len)180 int CWAudioGetAdlibSoundRaw(
181 const CWAudio *audio, const int i, const char **data, size_t *len)
182 {
183 int err = 0;
184 const int off = audio->head.offsets[i + audio->startAdlibSounds];
185 *len = audio->head.offsets[i + audio->startAdlibSounds + 1] - off;
186 if (*len == 0)
187 {
188 fprintf(stderr, "No audio len for track %d\n", i);
189 err = -1;
190 goto bail;
191 }
192 *data = &audio->data[off];
193
194 bail:
195 return err;
196 }
197
CWAudioGetAdlibSound(const CWAudio * audio,const int idx,char ** data,size_t * len)198 int CWAudioGetAdlibSound(
199 const CWAudio *audio, const int idx, char **data, size_t *len)
200 {
201 *data = NULL;
202 *len = 0;
203 const char *rawData;
204 size_t rawLen;
205 int err = CWAudioGetAdlibSoundRaw(audio, idx, &rawData, &rawLen);
206 if (err != 0)
207 {
208 goto bail;
209 }
210
211 const AdLibSound *sound = (const AdLibSound *)rawData;
212 const uint8_t alBlock = ((sound->block & 7) << 2) | 0x20;
213 AlSetChanInst(&sound->inst, 0);
214
215 const uint8_t *alSound = sound->data;
216 *len = sound->length * SAMPLES_PER_MUSIC_TICK * SOUND_TICKS *
217 MUSIC_AUDIO_CHANNELS * 2;
218 *data = malloc(*len);
219 int16_t *stream16 = (int16_t *)*data;
220 for (int alLengthLeft = (int)sound->length; alLengthLeft > 0;
221 alLengthLeft--)
222 {
223 // THIS is the way the original Wolfenstein 3-D code handled it!
224 if (*alSound)
225 {
226 alOut(alFreqL, *alSound);
227 alOut(alFreqH, alBlock);
228 }
229 else
230 alOut(alFreqH, 0);
231 alSound++;
232
233 for (int i = 0; i < SOUND_TICKS; i++)
234 {
235 YM3812UpdateOne(oplChip, stream16, SAMPLES_PER_MUSIC_TICK);
236 stream16 += SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS;
237 }
238 }
239 alOut(alFreqH, 0);
240
241 return err;
242
243 bail:
244 if (err != 0)
245 {
246 free(*data);
247 *data = NULL;
248 }
249 return err;
250 }
251
CWAudioGetMusicRaw(const CWAudio * audio,const int i,const char ** data,size_t * len)252 int CWAudioGetMusicRaw(
253 const CWAudio *audio, const int i, const char **data, size_t *len)
254 {
255 int err = 0;
256 const int off = audio->head.offsets[i + audio->startMusic];
257 *len = audio->head.offsets[i + audio->startMusic + 1] - off;
258 if (*len == 0)
259 {
260 fprintf(stderr, "No music len for track %d\n", i);
261 err = -1;
262 goto bail;
263 }
264 if (*len == 88)
265 {
266 *len = 0;
267 goto bail;
268 }
269 *data = &audio->data[off];
270
271 bail:
272 return err;
273 }
274
CWAudioGetMusic(const CWAudio * audio,const int idx,char ** data,size_t * len)275 int CWAudioGetMusic(
276 const CWAudio *audio, const int idx, char **data, size_t *len)
277 {
278 *data = NULL;
279 *len = 0;
280 const char *rawData;
281 size_t rawLen;
282 int err = CWAudioGetMusicRaw(audio, idx, &rawData, &rawLen);
283 if (err != 0)
284 {
285 goto bail;
286 }
287 if (rawLen == 0)
288 {
289 goto bail;
290 }
291
292 for (int i = 0; i < OPL_CHANNELS; i++)
293 {
294 AlSetChanInst(&ChannelRelease, i);
295 }
296
297 // Measure length of music
298 const uint16_t *sqHack = (const uint16_t *)rawData;
299 int sqHackLen;
300 if (*sqHack == 0)
301 {
302 // LumpLength?
303 sqHackLen = (int)rawLen;
304 }
305 else
306 {
307 sqHackLen = *sqHack++;
308 }
309 const uint16_t *sqHackPtr = sqHack;
310
311 int sqHackTime = 0;
312 int alTimeCount;
313 for (alTimeCount = 0; sqHackLen > 0; alTimeCount++)
314 {
315 do
316 {
317 if (sqHackTime > alTimeCount)
318 break;
319 sqHackTime = alTimeCount + *(sqHackPtr + 1);
320 sqHackPtr += 2;
321 sqHackLen -= 4;
322 } while (sqHackLen > 0);
323 }
324
325 // Decode music
326 // 2 bytes per sample (16-bit audio fmt)
327 *len = alTimeCount * SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS * 2;
328 *data = malloc(*len);
329 int16_t *stream16 = (int16_t *)*data;
330
331 sqHack = (const uint16_t *)rawData;
332 if (*sqHack == 0)
333 {
334 // LumpLength?
335 sqHackLen = (int)rawLen;
336 }
337 else
338 {
339 sqHackLen = *sqHack++;
340 }
341 sqHackPtr = sqHack;
342 sqHackTime = 0;
343 for (alTimeCount = 0; sqHackLen > 0; alTimeCount++)
344 {
345 do
346 {
347 if (sqHackTime > alTimeCount)
348 break;
349 sqHackTime = alTimeCount + *(sqHackPtr + 1);
350 alOut(
351 *(const uint8_t *)sqHackPtr,
352 *(((const uint8_t *)sqHackPtr) + 1));
353 sqHackPtr += 2;
354 sqHackLen -= 4;
355 } while (sqHackLen > 0);
356
357 YM3812UpdateOne(oplChip, stream16, SAMPLES_PER_MUSIC_TICK);
358
359 stream16 += SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS;
360 }
361
362 return err;
363
364 bail:
365 if (err != 0)
366 {
367 free(*data);
368 *data = NULL;
369 }
370 return err;
371 }
372
CWAudioGetLevelMusic(const CWMapType type,const int level)373 int CWAudioGetLevelMusic(const CWMapType type, const int level)
374 {
375 switch (type)
376 {
377 case CWMAPTYPE_WL1:
378 case CWMAPTYPE_WL6:
379 return CWAudioWL6GetLevelMusic(level);
380 case CWMAPTYPE_SOD:
381 return CWAudioSODGetLevelMusic(level);
382 }
383 return -1;
384 }
385
CWAudioGetSong(const CWMapType type,const CWSongType song)386 int CWAudioGetSong(const CWMapType type, const CWSongType song)
387 {
388 switch (type)
389 {
390 case CWMAPTYPE_WL1:
391 case CWMAPTYPE_WL6:
392 return CWAudioWL6GetSong(song);
393 case CWMAPTYPE_SOD:
394 return CWAudioSODGetSong(song);
395 }
396 return -1;
397 }
398