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