1 /*
2 Copyright (c) 2009-2011 Tero Lindeman (kometbomb)
3 
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use,
8 copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following
11 conditions:
12 
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #include "cyd.h"
27 #include "macros.h"
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #ifdef ENABLEAUDIODUMP
33 #include <time.h>
34 #endif
35 
36 #include "cyddefs.h"
37 #include "cydwave.h"
38 #include "freqs.h"
39 #include "cydosc.h"
40 
41 #ifndef USENATIVEAPIS
42 # ifndef NOSDL_MIXER
43 # include "SDL_mixer.h"
44 # endif
45 #else
46 
47 # ifdef WIN32
48 # endif
49 
50 #endif
51 
52 #define envspd(cyd,slope) (slope!=0?(((Uint64)0xff0000 / ((slope) * (slope) * 256 / (ENVELOPE_SCALE * ENVELOPE_SCALE))) * CYD_BASE_FREQ / cyd->sample_rate):((Uint64)0xff0000 * CYD_BASE_FREQ / cyd->sample_rate))
53 
54 // used lfsr-generator <http://lfsr-generator.sourceforge.net/> for this:
55 
shift_lfsr(Uint32 * v,int tap_0,int tap_1)56 inline static void shift_lfsr(Uint32 *v, int tap_0, int tap_1)
57 {
58   typedef unsigned int T;
59   const T zero = (T)(0);
60   const T lsb = zero + (T)(1);
61   const T feedback = (
62     (lsb << (tap_0)) ^
63     (lsb << (tap_1))
64   );
65   *v = (*v >> 1) ^ ((zero - (*v & lsb)) & feedback);
66 }
67 
68 
cyd_init_channel(CydEngine * cyd,CydChannel * chn)69 static void cyd_init_channel(CydEngine *cyd, CydChannel *chn)
70 {
71 	memset(chn, 0, sizeof(*chn));
72 	chn->pw = 0x400;
73 	cyd_set_filter_coeffs(cyd, chn, 2047, 0);
74 #ifdef STEREOOUTPUT
75 	cyd_set_panning(cyd, chn, CYD_PAN_CENTER);
76 #endif
77 
78 	for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
79 	{
80 		chn->subosc[s].random = RANDOM_SEED;
81 		chn->subosc[s].reg4 = chn->subosc[s].reg5 = chn->subosc[s].reg9 = 1;
82 	}
83 
84 #ifndef CYD_DISABLE_FM
85 	cydfm_init(&chn->fm);
86 #endif
87 }
88 
89 
cyd_init_log_tables(CydEngine * cyd)90 static void cyd_init_log_tables(CydEngine *cyd)
91 {
92 	for (int i = 0 ; i < LUT_SIZE ; ++i)
93 	{
94 		cyd->lookup_table[i] = i * (i/2) / ((LUT_SIZE*LUT_SIZE / 65536)/2);
95 	}
96 
97 #ifndef CYD_DISABLE_BUZZ
98 	for (int i = 0 ; i < YM_LUT_SIZE ; ++i)
99 	{
100 		static const int ymVolumeTable[16] = { 62,161,265,377,580,774,1155,1575,2260,3088,4570,6233,9330,13187,21220,32767}; // from leonard's code
101 		cyd->lookup_table_ym[i] = ymVolumeTable[i]; //(Uint32)32767 * (Uint32)(i+1) * (Uint32)(i+1) * (Uint32)(i+1) / (Uint32)(YM_LUT_SIZE * YM_LUT_SIZE * YM_LUT_SIZE);
102 	}
103 
104 	cyd->lookup_table_ym[0] = 0;
105 #endif
106 }
107 
108 
cyd_reset_wavetable(CydEngine * cyd)109 void cyd_reset_wavetable(CydEngine *cyd)
110 {
111 #ifndef CYD_DISABLE_WAVETABLE
112 	memset(cyd->wavetable_entries, 0, sizeof(cyd->wavetable_entries[0]) * CYD_WAVE_MAX_ENTRIES);
113 
114 	for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i)
115 	{
116 		cyd_wave_entry_init(&cyd->wavetable_entries[i], NULL, 0, 0, 0, 0, 0);
117 	}
118 #endif
119 }
120 
121 
cyd_init(CydEngine * cyd,Uint16 sample_rate,int channels)122 void cyd_init(CydEngine *cyd, Uint16 sample_rate, int channels)
123 {
124 	memset(cyd, 0, sizeof(*cyd));
125 	cyd->sample_rate = sample_rate;
126 	cyd->lookup_table = malloc(sizeof(*cyd->lookup_table) * LUT_SIZE);
127 	cyd->oversample = MAX_OVERSAMPLE;
128 #ifndef CYD_DISABLE_BUZZ
129 	cyd->lookup_table_ym = malloc(sizeof(*cyd->lookup_table) * YM_LUT_SIZE);
130 #endif
131 
132 #ifndef USENATIVEAPIS
133 
134 # ifdef USESDLMUTEXES
135 	cyd->mutex = SDL_CreateMutex();
136 # endif
137 
138 #else
139 
140 # ifdef WIN32
141 	InitializeCriticalSection(&cyd->mutex);
142 	InitializeCriticalSection(&cyd->thread_lock);
143 # endif
144 
145 #endif
146 
147 	cyd_init_log_tables(cyd);
148 
149 	for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i)
150 		cydfx_init(&cyd->fx[i], sample_rate);
151 #ifndef CYD_DISABLE_WAVETABLE
152 	cyd->wavetable_entries = calloc(sizeof(cyd->wavetable_entries[0]), CYD_WAVE_MAX_ENTRIES);
153 
154 	cyd_reset_wavetable(cyd);
155 #endif
156 
157 	cyd_reserve_channels(cyd, channels);
158 }
159 
160 
cyd_set_oversampling(CydEngine * cyd,int oversampling)161 void cyd_set_oversampling(CydEngine *cyd, int oversampling)
162 {
163 	cyd->oversample = oversampling;
164 }
165 
166 
cyd_reserve_channels(CydEngine * cyd,int channels)167 void cyd_reserve_channels(CydEngine *cyd, int channels)
168 {
169 	debug("Reserving %d Cyd channels", channels);
170 	cyd_lock(cyd, 1);
171 
172 	cyd->n_channels = channels;
173 
174 	if (cyd->n_channels > CYD_MAX_CHANNELS)
175 		cyd->n_channels = CYD_MAX_CHANNELS;
176 
177 	if (cyd->channel)
178 		free(cyd->channel);
179 
180 	cyd->channel = calloc(sizeof(*cyd->channel), CYD_MAX_CHANNELS);
181 
182 	cyd_reset(cyd);
183 
184 	cyd_lock(cyd, 0);
185 }
186 
187 
cyd_deinit(CydEngine * cyd)188 void cyd_deinit(CydEngine *cyd)
189 {
190 	if (cyd->lookup_table)
191 	{
192 		free(cyd->lookup_table);
193 		cyd->lookup_table = NULL;
194 	}
195 
196 #ifndef CYD_DISABLE_BUZZ
197 	if (cyd->lookup_table_ym)
198 	{
199 		free(cyd->lookup_table_ym);
200 		cyd->lookup_table_ym = NULL;
201 	}
202 #endif
203 
204 	if (cyd->channel)
205 	{
206 		free(cyd->channel);
207 		cyd->channel = NULL;
208 	}
209 
210 	for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i)
211 		cydfx_deinit(&cyd->fx[i]);
212 
213 #ifndef USENATIVEAPIS
214 
215 # ifdef USESDLMUTEXES
216 	if (cyd->mutex)
217 		SDL_DestroyMutex(cyd->mutex);
218 	cyd->mutex = NULL;
219 # endif
220 
221 #else
222 
223 # ifdef WIN32
224 	DeleteCriticalSection(&cyd->mutex);
225 	DeleteCriticalSection(&cyd->thread_lock);
226 # endif
227 
228 #endif
229 
230 #ifndef CYD_DISABLE_WAVETABLE
231 	if (cyd->wavetable_entries)
232 	{
233 		for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i)
234 			cyd_wave_entry_deinit(&cyd->wavetable_entries[i]);
235 
236 		free(cyd->wavetable_entries);
237 		cyd->wavetable_entries = NULL;
238 	}
239 #endif
240 }
241 
242 
cyd_reset(CydEngine * cyd)243 void cyd_reset(CydEngine *cyd)
244 {
245 	for (int i = 0 ; i < cyd->n_channels ; ++i)
246 	{
247 		cyd_init_channel(cyd, &cyd->channel[i]);
248 		cyd->channel[i].sync_source = i;
249 	}
250 }
251 
252 
cyd_cycle_adsr(const CydEngine * eng,Uint32 flags,Uint32 ym_env_shape,CydAdsr * adsr)253 Uint32 cyd_cycle_adsr(const CydEngine *eng, Uint32 flags, Uint32 ym_env_shape, CydAdsr *adsr)
254 {
255 	if (!(flags & CYD_CHN_ENABLE_YM_ENV))
256 	{
257 #ifndef CYD_DISABLE_ENVELOPE
258 		// SID style ADSR envelope
259 
260 		switch (adsr->envelope_state)
261 		{
262 			case SUSTAIN:
263 			case DONE: return flags; break;
264 
265 			case ATTACK:
266 
267 			adsr->envelope += adsr->env_speed;
268 
269 			if (adsr->envelope >= 0xff0000)
270 			{
271 				adsr->envelope_state = DECAY;
272 				adsr->envelope=0xff0000;
273 				adsr->env_speed = envspd(eng, adsr->d);
274 			}
275 
276 			break;
277 
278 			case DECAY:
279 
280 				if (adsr->envelope > ((Uint32)adsr->s << 19) + adsr->env_speed)
281 					adsr->envelope -= adsr->env_speed;
282 				else
283 				{
284 					adsr->envelope = (Uint32)adsr->s << 19;
285 					adsr->envelope_state = (adsr->s == 0) ? RELEASE : SUSTAIN;
286 					adsr->env_speed = envspd(eng, adsr->r);;
287 				}
288 
289 			break;
290 
291 			case RELEASE:
292 			if (adsr->envelope > adsr->env_speed)
293 			{
294 				adsr->envelope -= adsr->env_speed;
295 			}
296 			else
297 			{
298 				adsr->envelope_state = DONE;
299 				if ((flags & (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) != (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) flags &= ~CYD_CHN_ENABLE_GATE;
300 				adsr->envelope = 0;
301 			}
302 			break;
303 		}
304 #endif
305 	}
306 	else
307 	{
308 #ifndef CYD_DISABLE_BUZZ
309 		// YM2149 style envelope HOLD is not processed
310 
311 		switch (adsr->envelope_state)
312 		{
313 			case ATTACK:
314 
315 				adsr->envelope += adsr->env_speed;
316 
317 				if (adsr->envelope >= YM_LENGTH)
318 				{
319 					if (ym_env_shape & CYD_YM_ENV_ALT)
320 					{
321 						adsr->envelope = YM_LENGTH - (adsr->envelope - YM_LENGTH);
322 						adsr->envelope_state = DECAY;
323 					}
324 					else
325 					{
326 						adsr->envelope &= YM_LENGTH - 1;
327 						adsr->envelope_state = ATTACK;
328 					}
329 				}
330 
331 			break;
332 
333 			case DECAY:
334 
335 				if (adsr->envelope >= adsr->env_speed)
336 					adsr->envelope -= adsr->env_speed;
337 				else
338 				{
339 					if (ym_env_shape & CYD_YM_ENV_ALT)
340 					{
341 						adsr->envelope = (Uint32)adsr->env_speed - adsr->envelope;
342 						adsr->envelope_state = ATTACK;
343 					}
344 					else
345 					{
346 						adsr->envelope -= adsr->env_speed;
347 						adsr->envelope &= YM_LENGTH - 1;
348 						adsr->envelope_state = DECAY;
349 					}
350 				}
351 
352 			break;
353 
354 			case RELEASE:
355 				adsr->envelope_state = DONE;
356 				if ((flags & (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) != (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) flags &= ~CYD_CHN_ENABLE_GATE;
357 				adsr->envelope = 0;
358 			break;
359 
360 			default: break;
361 		}
362 #endif
363 	}
364 
365 	return flags;
366 }
367 
368 
369 #ifndef CYD_DISABLE_LFSR
run_lfsrs(CydChannel * chn)370 static void run_lfsrs(CydChannel *chn)
371 {
372 	for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
373 	{
374 		shift_lfsr(&chn->subosc[s].reg4, 4, 3);
375 		shift_lfsr(&chn->subosc[s].reg5, 5, 3);
376 
377 		if (chn->lfsr_type & 8)
378 			shift_lfsr(&chn->subosc[s].reg9, 9, 5);
379 		else
380 			shift_lfsr(&chn->subosc[s].reg9, 17, 14);
381 	}
382 }
383 #endif
384 
385 
cyd_cycle_channel(CydEngine * cyd,CydChannel * chn)386 static void cyd_cycle_channel(CydEngine *cyd, CydChannel *chn)
387 {
388 	chn->flags = cyd_cycle_adsr(cyd, chn->flags, chn->ym_env_shape, &chn->adsr);
389 
390 	if (chn->flags & CYD_CHN_ENABLE_WAVE)
391 	{
392 		for (int i = 0 ; i < CYD_SUB_OSCS ; ++i)
393 		{
394 			cyd_wave_cycle(&chn->subosc[i].wave, chn->wave_entry);
395 		}
396 	}
397 
398 #ifndef CYD_DISABLE_FM
399 	if (chn->flags & CYD_CHN_ENABLE_FM) cydfm_cycle(cyd, &chn->fm);
400 #endif
401 	// cycle random lfsr
402 }
403 
404 
cyd_sync_channel(CydEngine * cyd,CydChannel * chn)405 static void cyd_sync_channel(CydEngine *cyd, CydChannel *chn)
406 {
407 	if ((chn->flags & CYD_CHN_ENABLE_SYNC) && cyd->channel[chn->sync_source].sync_bit)
408 	{
409 		for (int i = 0 ; i < CYD_SUB_OSCS ; ++i)
410 		{
411 			chn->subosc[i].wave.acc = 0;
412 			chn->subosc[i].wave.direction = 0;
413 			chn->subosc[i].accumulator = 0;
414 			chn->subosc[i].random = RANDOM_SEED;
415 			chn->subosc[i].reg4 = 1;
416 			chn->subosc[i].reg5 = 1;
417 			chn->subosc[i].reg9 = 1;
418 			chn->subosc[i].lfsr_ctr = 0;
419 		}
420 	}
421 }
422 
423 
cyd_advance_oscillators(CydEngine * cyd,CydChannel * chn)424 static void cyd_advance_oscillators(CydEngine *cyd, CydChannel *chn)
425 {
426 	for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
427 	{
428 		Uint32 prev_acc = chn->subosc[s].accumulator;
429 		chn->subosc[s].accumulator = (chn->subosc[s].accumulator + (Uint32)chn->subosc[s].frequency);
430 
431 		/* only subosc #0 can set the sync bit */
432 
433 		if (s == 0)
434 			chn->sync_bit |= chn->subosc[s].accumulator & ACC_LENGTH;
435 
436 		chn->subosc[s].accumulator &= ACC_LENGTH - 1;
437 
438 		if ((prev_acc & (ACC_LENGTH/32)) != (chn->subosc[s].accumulator & (ACC_LENGTH/32)))
439 		{
440 			if (chn->flags & CYD_CHN_ENABLE_METAL)
441 			{
442 				shift_lfsr(&chn->subosc[s].random, 0xe, 8);
443 				chn->subosc[s].random &= (1 << (0xe + 1)) - 1;
444 			}
445 			else
446 			{
447 				shift_lfsr(&chn->subosc[s].random, 22, 17);
448 				chn->subosc[s].random &= (1 << (22 + 1)) - 1;
449 			}
450 		}
451 
452 #ifndef CYD_DISABLE_LFSR
453 		if (chn->flags & CYD_CHN_ENABLE_LFSR)
454 		{
455 			chn->subosc[s].lfsr_acc = (chn->subosc[s].lfsr & 1) ? (WAVE_AMP - 1) : 0;
456 
457 			if (chn->subosc[s].lfsr_ctr >= chn->subosc[s].lfsr_period)
458 			{
459 				chn->subosc[s].lfsr_ctr = 0;
460 
461 				switch (chn->lfsr_type & 3)
462 				{
463 					case 0:
464 						chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg5 & chn->subosc[s].reg9 & 1);
465 						break;
466 
467 					case 1:
468 					case 3:
469 						chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg5 & 1);
470 						break;
471 
472 					case 2:
473 						chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg5 & chn->subosc[s].reg4 & 1);
474 						break;
475 
476 					case 4:
477 						chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg9 & 1);
478 						break;
479 
480 					case 5:
481 					case 7:
482 						chn->subosc[s].lfsr ^= 1;
483 						break;
484 
485 					case 6:
486 						chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg4 & 1);
487 						break;
488 				}
489 			}
490 
491 			++chn->subosc[s].lfsr_ctr;
492 
493 			run_lfsrs(chn);
494 		}
495 #endif
496 	}
497 }
498 
499 
cyd_output_channel(CydEngine * cyd,CydChannel * chn)500 static Sint32 cyd_output_channel(CydEngine *cyd, CydChannel *chn)
501 {
502 	Sint32 ovr = 0;
503 
504 	chn->sync_bit = 0;
505 
506 #ifndef CYD_DISABLE_FM
507 	const Uint32 mod = (chn->flags & CYD_CHN_ENABLE_FM) ? cydfm_modulate(cyd, &chn->fm, 0) : 0;
508 #endif
509 
510 	for (int i = 0 ; i < (1 << cyd->oversample) ; ++i)
511 	{
512 		for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
513 		{
514 			if (chn->subosc[s].frequency != 0)
515 			{
516 #ifdef CYD_DISABLE_FM
517 				Uint32 accumulator = chn->subosc[s].accumulator;
518 #else
519 				Uint32 accumulator = chn->subosc[s].accumulator + mod;
520 #endif
521 				ovr += cyd_osc(chn->flags, accumulator % ACC_LENGTH, chn->pw, chn->subosc[s].random, chn->subosc[s].lfsr_acc) - WAVE_AMP / 2;
522 			}
523 		}
524 
525 		cyd_advance_oscillators(cyd, chn); // Need to move the oscillators per every oversample subcycle
526 
527 #ifndef CYD_DISABLE_FM
528 		cydfm_cycle_oversample(cyd, &chn->fm);
529 #endif
530 	}
531 
532 	return (ovr >> cyd->oversample);
533 }
534 
535 
cyd_env_output(const CydEngine * cyd,Uint32 chn_flags,const CydAdsr * adsr,Sint32 input)536 Sint32 cyd_env_output(const CydEngine *cyd, Uint32 chn_flags, const CydAdsr *adsr, Sint32 input)
537 {
538 	if (chn_flags & CYD_CHN_ENABLE_YM_ENV)
539 	{
540 #ifndef CYD_DISABLE_BUZZ
541 		int idx = adsr->envelope * (Uint32)YM_LUT_SIZE / YM_LENGTH;
542 		return input * cyd->lookup_table_ym[idx % YM_LUT_SIZE] / 32768 * (Sint32)(adsr->volume) / MAX_VOLUME;
543 #else
544 		return input * (Sint32)(adsr->volume) / MAX_VOLUME;
545 #endif
546 	}
547 	else
548 	{
549 #ifndef CYD_DISABLE_ENVELOPE
550 		if (adsr->envelope_state == ATTACK)
551 			return ((Sint64)input * ((Sint32)adsr->envelope / 0x10000) / 256) * (Sint32)(adsr->volume) / MAX_VOLUME;
552 		else
553 			return ((Sint64)input * (cyd->lookup_table[(adsr->envelope / (65536*256 / LUT_SIZE) ) & (LUT_SIZE - 1)]) / 65536) * (Sint32)(adsr->volume) / MAX_VOLUME;
554 #else
555 		return input * (Sint32)(adsr->volume) / MAX_VOLUME;
556 #endif
557 	}
558 }
559 
560 
561 #ifdef STEREOOUTPUT
cyd_output(CydEngine * cyd,Sint32 * left,Sint32 * right)562 static void cyd_output(CydEngine *cyd, Sint32 *left, Sint32 *right)
563 #else
564 static Sint32 cyd_output(CydEngine *cyd)
565 #endif
566 {
567 #ifdef STEREOOUTPUT
568 	*left = *right = 0;
569 	Sint32 fx_l[CYD_MAX_FX_CHANNELS] = {0}, fx_r[CYD_MAX_FX_CHANNELS] = {0};
570 #else
571 	Sint32 v = 0, fx_input[CYD_MAX_FX_CHANNELS] = {0};
572 #endif
573 	Sint32 s[CYD_MAX_CHANNELS];
574 
575 	for (int i = 0 ; i < cyd->n_channels ; ++i)
576 	{
577 		s[i] = (Sint32)cyd_output_channel(cyd, &cyd->channel[i]);
578 #ifndef CYD_DISABLE_WAVETABLE
579 		if ((cyd->channel[i].flags & CYD_CHN_ENABLE_WAVE) && cyd->channel[i].wave_entry && !(cyd->channel[i].flags & CYD_CHN_WAVE_OVERRIDE_ENV))
580 		{
581 			for (int sub = 0 ; sub < CYD_SUB_OSCS ; ++sub)
582 			{
583 				if (cyd->channel[i].subosc[sub].wave.playing && cyd->channel[i].subosc[sub].wave.frequency != 0)
584 				{
585 #ifdef CYD_DISABLE_FM
586 					CydWaveAcc accumulator = cyd->channel[i].subosc[sub].wave.acc;
587 #else
588 					CydWaveAcc accumulator = (cyd->channel[i].flags & CYD_CHN_ENABLE_FM) ? cydfm_modulate_wave(cyd, &cyd->channel[i].fm, cyd->channel[i].wave_entry, cyd->channel[i].subosc[sub].wave.acc) : cyd->channel[i].subosc[sub].wave.acc;
589 #endif
590 					s[i] += cyd_wave_get_sample(&cyd->channel[i].subosc[sub].wave, cyd->channel[i].wave_entry, accumulator);
591 				}
592 			}
593 		}
594 #endif
595 	}
596 
597 	for (int i = 0 ; i < cyd->n_channels ; ++i)
598 	{
599 		CydChannel *chn = &cyd->channel[i];
600 		Sint32 o = 0;
601 		if (chn->flags & CYD_CHN_ENABLE_GATE)
602 		{
603 			if (chn->flags & CYD_CHN_ENABLE_RING_MODULATION)
604 			{
605 				o = cyd_env_output(cyd, chn->flags, &chn->adsr, s[i] * (s[chn->ring_mod] + (WAVE_AMP / 2)) / WAVE_AMP);
606 			}
607 			else
608 			{
609 				o = cyd_env_output(cyd, chn->flags, &chn->adsr, s[i]);
610 			}
611 
612 #ifndef CYD_DISABLE_WAVETABLE
613 			if ((cyd->channel[i].flags & CYD_CHN_ENABLE_WAVE) && cyd->channel[i].wave_entry && (cyd->channel[i].flags & CYD_CHN_WAVE_OVERRIDE_ENV))
614 			{
615 				for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
616 				{
617 					if (cyd->channel[i].subosc[s].wave.playing && cyd->channel[i].subosc[s].wave.frequency != 0)
618 					{
619 #ifdef CYD_DISABLE_FM
620 						CydWaveAcc accumulator = cyd->channel[i].subosc[s].wave.acc;
621 #else
622 						CydWaveAcc accumulator = (cyd->channel[i].flags & CYD_CHN_ENABLE_FM) ? cydfm_modulate_wave(cyd, &cyd->channel[i].fm, cyd->channel[i].wave_entry, cyd->channel[i].subosc[s].wave.acc) : cyd->channel[i].subosc[s].wave.acc;
623 #endif
624 						o += cyd_wave_get_sample(&cyd->channel[i].subosc[s].wave, chn->wave_entry, accumulator) * (Sint32)(chn->adsr.volume) / MAX_VOLUME;
625 					}
626 				}
627 			}
628 #endif
629 
630 #ifndef CYD_DISABLE_FILTER
631 			if (chn->flags & CYD_CHN_ENABLE_FILTER)
632 			{
633 				cydflt_cycle(&chn->flt, o);
634 				switch (chn->flttype)
635 				{
636 					case FLT_BP: o = cydflt_output_bp(&chn->flt); break;
637 					default: case FLT_LP: o = cydflt_output_lp(&chn->flt); break;
638 					case FLT_HP: o = cydflt_output_hp(&chn->flt); break;
639 				}
640 			}
641 #endif
642 
643 #ifdef STEREOOUTPUT
644 			Sint32 ol = o * chn->gain_left / CYD_STEREO_GAIN, or = o * chn->gain_right / CYD_STEREO_GAIN;
645 #endif
646 
647 			if (chn->flags & CYD_CHN_ENABLE_FX)
648 			{
649 #ifdef STEREOOUTPUT
650 				fx_l[chn->fx_bus] += ol;
651 				fx_r[chn->fx_bus] += or;
652 #else
653 				fx_input[chn->fx_bus] += o;
654 #endif
655 			}
656 			else
657 			{
658 #ifdef STEREOOUTPUT
659 				*left += ol;
660 				*right += or;
661 #else
662 				v += o;
663 #endif
664 			}
665 		}
666 	}
667 
668 	for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i)
669 	{
670 #ifdef STEREOOUTPUT
671 		Sint32 l, r;
672 		cydfx_output(&cyd->fx[i], fx_l[i], fx_r[i], &l, &r);
673 		*left += l;
674 		*right += r;
675 #else
676 		v += cydfx_output(&cyd->fx[i], fx_input[i]);
677 #endif
678 	}
679 
680 #ifndef STEREOOUTPUT
681 	return v;
682 #endif
683 }
684 
685 
cyd_cycle(CydEngine * cyd)686 static void cyd_cycle(CydEngine *cyd)
687 {
688 	for (int i = 0 ; i < cyd->n_channels ; ++i)
689 	{
690 		cyd_cycle_channel(cyd, &cyd->channel[i]);
691 	}
692 
693 	for (int i = 0 ; i < cyd->n_channels ; ++i)
694 	{
695 		cyd_sync_channel(cyd, &cyd->channel[i]);
696 	}
697 }
698 
699 
700 #ifdef NOSDL_MIXER
cyd_output_buffer(void * udata,Uint8 * _stream,int len)701 void cyd_output_buffer(void *udata, Uint8 *_stream, int len)
702 #else
703 void cyd_output_buffer(int chan, void *_stream, int len, void *udata)
704 #endif
705 {
706 	CydEngine *cyd = udata;
707 	Sint16 * stream = (void*)_stream;
708 	cyd->samples_output = 0;
709 
710 	for (int i = 0 ; i < len ; i += sizeof(Sint16), ++stream, ++cyd->samples_output)
711 	{
712 
713 #ifndef USENATIVEAPIS
714 
715 #ifndef USESDLMUTEXES
716 #ifdef DEBUG
717 		Uint32 waittime = SDL_GetTicks();
718 #endif
719 		while (cyd->lock_request)
720 		{
721 #ifdef DEBUG
722 			if (SDL_GetTicks() - waittime > 5000)
723 			{
724 				warning("Deadlock from cyd_output_buffer");
725 				waittime = SDL_GetTicks();
726 			}
727 #endif
728 			SDL_Delay(1);
729 		}
730 #endif
731 
732 #endif
733 
734 		if (cyd->flags & CYD_PAUSED)
735 		{
736 			i += BUFFER_GRANULARITY * 2 * sizeof(Sint16);
737 			stream += BUFFER_GRANULARITY * 2;
738 			continue;
739 		}
740 
741 		cyd_lock(cyd, 1);
742 
743 		for (int g = 0 ; g < BUFFER_GRANULARITY && i < len ; i += sizeof(Sint16)*2, stream += 2, ++cyd->samples_output)
744 		{
745 
746 			if (cyd->callback && cyd->callback_counter-- == 0)
747 			{
748 				cyd->callback_counter = cyd->callback_period-1;
749 				if (!cyd->callback(cyd->callback_parameter))
750 				{
751 					cyd_lock(cyd, 0);
752 					return;
753 				}
754 			}
755 
756 #ifdef STEREOOUTPUT
757 			Sint32 output, left, right;
758 			cyd_output(cyd, &left, &right);
759 			output = (left + right) / 2;
760 #else
761 			Sint32 output = cyd_output(cyd);
762 #endif
763 
764 #ifdef NOSDL_MIXER
765 			Sint32 o = (output * PRE_GAIN) / PRE_GAIN_DIVISOR;
766 #else
767 			Sint32 o = (Sint32)*(Sint16*)stream + (output * PRE_GAIN) / PRE_GAIN_DIVISOR;
768 #endif
769 
770 			if (o < -32768) o = -32768;
771 			else if (o > 32767) o = 32767;
772 
773 			*(Sint16*)stream = o;
774 
775 			cyd_cycle(cyd);
776 		}
777 
778 		cyd_lock(cyd, 0);
779 	}
780 
781 }
782 
783 
784 #ifdef NOSDL_MIXER
cyd_output_buffer_stereo(void * udata,Uint8 * _stream,int len)785 void cyd_output_buffer_stereo(void *udata, Uint8 *_stream, int len)
786 #else
787 void cyd_output_buffer_stereo(int chan, void *_stream, int len, void *udata)
788 #endif
789 {
790 	CydEngine *cyd = udata;
791 	Sint16 *stream = (void*)_stream;
792 	cyd->samples_output = 0;
793 	cyd->flags &= ~CYD_CLIPPING;
794 
795 	for (int i = 0 ; i < len ; )
796 	{
797 #ifndef USENATIVEAPIS
798 
799 #ifndef USESDLMUTEXES
800 #ifdef DEBUG
801 		Uint32 waittime = SDL_GetTicks();
802 #endif
803 		while (cyd->lock_request)
804 		{
805 #ifdef DEBUG
806 			if (SDL_GetTicks() - waittime > 5000)
807 			{
808 				warning("Deadlock from cyd_output_buffer");
809 				waittime = SDL_GetTicks();
810 			}
811 #endif
812 			SDL_Delay(1);
813 		}
814 #endif
815 
816 #endif
817 
818 		if (cyd->flags & CYD_PAUSED)
819 		{
820 			i += BUFFER_GRANULARITY * 2 * sizeof(Sint16);
821 			stream += BUFFER_GRANULARITY * 2;
822 			continue;
823 		}
824 
825 		cyd_lock(cyd, 1);
826 
827 		for (int g = 0 ; g < BUFFER_GRANULARITY && i < len ; i += sizeof(Sint16)*2, stream += 2, ++cyd->samples_output)
828 		{
829 
830 			if (cyd->callback && cyd->callback_counter-- == 0)
831 			{
832 				cyd->callback_counter = cyd->callback_period-1;
833 				if (!cyd->callback(cyd->callback_parameter))
834 				{
835 					cyd_lock(cyd, 0);
836 					return;
837 				}
838 			}
839 
840 			Sint32 left, right;
841 #ifdef STEREOOUTPUT
842 			cyd_output(cyd, &left, &right);
843 #else
844 			left = right = cyd_output(cyd);
845 #endif
846 
847 #ifdef NOSDL_MIXER
848 			Sint32 o1 = (left * PRE_GAIN) / PRE_GAIN_DIVISOR;
849 #else
850 			Sint32 o1 = (Sint32)*(Sint16*)stream + (left * PRE_GAIN) / PRE_GAIN_DIVISOR;
851 #endif
852 
853 			if (o1 < -32768)
854 			{
855 				o1 = -32768;
856 				cyd->flags |= CYD_CLIPPING;
857 			}
858 			else if (o1 > 32767)
859 			{
860 				o1 = 32767;
861 				cyd->flags |= CYD_CLIPPING;
862 			}
863 
864 			*(Sint16*)stream = o1;
865 
866 #ifdef NOSDL_MIXER
867 			Sint32 o2 = (right * PRE_GAIN) / PRE_GAIN_DIVISOR;
868 #else
869 			Sint32 o2 = (Sint32)*((Sint16*)stream + 1) + (right * PRE_GAIN) / PRE_GAIN_DIVISOR;
870 #endif
871 
872 			if (o2 < -32768)
873 			{
874 				o2 = -32768;
875 				cyd->flags |= CYD_CLIPPING;
876 			}
877 			else if (o2 > 32767)
878 			{
879 				o2 = 32767;
880 				cyd->flags |= CYD_CLIPPING;
881 			}
882 
883 			*((Sint16*)stream + 1) = o2;
884 
885 			cyd_cycle(cyd);
886 			++cyd->samples_played;
887 		}
888 
889 		cyd_lock(cyd, 0);
890 	}
891 }
892 
893 
cyd_set_frequency(CydEngine * cyd,CydChannel * chn,int subosc,Uint16 frequency)894 void cyd_set_frequency(CydEngine *cyd, CydChannel *chn, int subosc, Uint16 frequency)
895 {
896 	if (frequency != 0)
897 	{
898 		chn->subosc[subosc].frequency = (Uint64)(ACC_LENGTH >> (cyd->oversample))/16 * (Uint64)(frequency) / (Uint64)cyd->sample_rate;
899 
900 #ifndef CYD_DISABLE_LFSR
901 		chn->subosc[subosc].lfsr_period = (Uint64)cyd->sample_rate * 16 / frequency;
902 #endif
903 	}
904 	else
905 		chn->subosc[subosc].frequency = 0;
906 
907 #ifndef CYD_DISABLE_FM
908 	if (subosc == 0)
909 		cydfm_set_frequency(cyd, &chn->fm, frequency);
910 #endif
911 }
912 
913 
cyd_set_wavetable_frequency(CydEngine * cyd,CydChannel * chn,int subosc,Uint16 frequency)914 void cyd_set_wavetable_frequency(CydEngine *cyd, CydChannel *chn, int subosc, Uint16 frequency)
915 {
916 #ifndef CYD_DISABLE_WAVETABLE
917 	if (frequency != 0 && chn->wave_entry)
918 	{
919 		chn->subosc[subosc].wave.frequency = (Uint64)WAVETABLE_RESOLUTION * (Uint64)chn->wave_entry->sample_rate / (Uint64)cyd->sample_rate * (Uint64)frequency / (Uint64)get_freq(chn->wave_entry->base_note);
920 	}
921 	else
922 	{
923 		chn->subosc[subosc].wave.playing = false;
924 		chn->subosc[subosc].wave.frequency = 0;
925 	}
926 #endif
927 }
928 
929 
cyd_set_env_frequency(CydEngine * cyd,CydChannel * chn,Uint16 frequency)930 void cyd_set_env_frequency(CydEngine *cyd, CydChannel *chn, Uint16 frequency)
931 {
932 #ifndef CYD_DISABLE_BUZZ
933 	chn->adsr.env_speed = (Uint64)YM_LENGTH/16 * (Uint64)frequency / (Uint64)cyd->sample_rate;
934 #endif
935 }
936 
937 
cyd_set_env_shape(CydChannel * chn,Uint8 shape)938 void cyd_set_env_shape(CydChannel *chn, Uint8 shape)
939 {
940 #ifndef CYD_DISABLE_BUZZ
941 	chn->ym_env_shape = shape;
942 
943 	if ((chn->flags & CYD_CHN_ENABLE_KEY_SYNC) || (chn->adsr.envelope_state == DONE || chn->adsr.envelope_state == SUSTAIN))
944 	{
945 		if (shape & CYD_YM_ENV_ATT)
946 		{
947 			chn->adsr.envelope = 0;
948 			chn->adsr.envelope_state = ATTACK;
949 		}
950 		else
951 		{
952 			chn->adsr.envelope = YM_LENGTH;
953 			chn->adsr.envelope_state = DECAY;
954 		}
955 	}
956 #endif
957 }
958 
959 
cyd_enable_gate(CydEngine * cyd,CydChannel * chn,Uint8 enable)960 void cyd_enable_gate(CydEngine *cyd, CydChannel *chn, Uint8 enable)
961 {
962 	if (enable)
963 	{
964 		if (!(chn->flags & CYD_CHN_ENABLE_YM_ENV))
965 		{
966 #ifndef CYD_DISABLE_ENVELOPE
967 			chn->adsr.envelope_state = ATTACK;
968 			chn->adsr.envelope = 0x0;
969 			chn->adsr.env_speed = envspd(cyd, chn->adsr.a);
970 			chn->flags = cyd_cycle_adsr(cyd, chn->flags, chn->ym_env_shape, &chn->adsr);
971 #ifndef CYD_DISABLE_FM
972 			chn->fm.adsr.envelope_state = ATTACK;
973 			chn->fm.adsr.envelope = chn->fm.attack_start << 19;
974 			chn->fm.adsr.env_speed = envspd(cyd, chn->fm.adsr.a);
975 			cyd_cycle_adsr(cyd, 0, 0, &chn->fm.adsr);
976 #endif
977 #endif
978 		}
979 
980 		if (chn->flags & CYD_CHN_ENABLE_KEY_SYNC)
981 		{
982 			for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
983 			{
984 				chn->subosc[s].accumulator = 0;
985 				chn->subosc[s].reg4 = chn->subosc[s].reg5 = chn->subosc[s].reg9 = 1;
986 				chn->subosc[s].lfsr_ctr = 0;
987 			}
988 
989 #ifndef CYD_DISABLE_FM
990 			chn->fm.accumulator = 0;
991 			chn->fm.wave.acc = 0;
992 #endif
993 		}
994 
995 		chn->flags |= CYD_CHN_ENABLE_GATE;
996 	}
997 	else
998 	{
999 		chn->flags &= ~CYD_CHN_WAVE_OVERRIDE_ENV;
1000 		chn->adsr.envelope_state = RELEASE;
1001 		chn->adsr.env_speed = envspd(cyd, chn->adsr.r);
1002 
1003 #ifndef CYD_DISABLE_FM
1004 		chn->fm.adsr.envelope_state = RELEASE;
1005 		chn->fm.adsr.env_speed = envspd(cyd, chn->fm.adsr.r);
1006 #endif
1007 	}
1008 }
1009 
1010 
cyd_set_waveform(CydChannel * chn,Uint32 wave)1011 void cyd_set_waveform(CydChannel *chn, Uint32 wave)
1012 {
1013 	chn->flags = (chn->flags & (~WAVEFORMS)) | (wave & WAVEFORMS);
1014 }
1015 
1016 
cyd_set_callback(CydEngine * cyd,int (* callback)(void *),void * param,Uint16 period)1017 void cyd_set_callback(CydEngine *cyd, int (*callback)(void*), void*param, Uint16 period)
1018 {
1019 	cyd_lock(cyd, 1);
1020 
1021 	cyd->samples_played	= 0;
1022 	cyd->callback_parameter = param;
1023 	cyd->callback = callback;
1024 	cyd->callback_period = cyd->sample_rate / period;
1025 	cyd->callback_counter = cyd->callback_counter % cyd->callback_period;
1026 
1027 	cyd_lock(cyd, 0);
1028 }
1029 
1030 
cyd_set_callback_rate(CydEngine * cyd,Uint16 period)1031 void cyd_set_callback_rate(CydEngine *cyd, Uint16 period)
1032 {
1033 	cyd_lock(cyd, 1);
1034 
1035 	cyd->callback_period = cyd->sample_rate / period;
1036 	cyd->callback_counter = cyd->callback_counter % cyd->callback_period;
1037 
1038 	cyd_lock(cyd, 0);
1039 }
1040 
1041 
1042 #ifdef USENATIVEAPIS
1043 # ifdef WIN32
1044 
fill_buffer(CydEngine * cyd)1045 static void fill_buffer(CydEngine *cyd)
1046 {
1047 	//waveOutUnprepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[cyd->waveout_hdr_idx],sizeof(WAVEHDR));
1048 
1049 #ifdef NOSDL_MIXER
1050 	cyd_output_buffer_stereo(cyd, cyd->waveout_hdr[cyd->waveout_hdr_idx].lpData, cyd->waveout_hdr[cyd->waveout_hdr_idx].dwBufferLength);
1051 #else
1052 	cyd_output_buffer_stereo(0, cyd->waveout_hdr[cyd->waveout_hdr_idx].lpData, cyd->waveout_hdr[cyd->waveout_hdr_idx].dwBufferLength, cyd);
1053 #endif
1054 
1055 	//waveOutPrepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[cyd->waveout_hdr_idx],sizeof(WAVEHDR));
1056 
1057 	cyd->waveout_hdr[cyd->waveout_hdr_idx].dwFlags = WHDR_PREPARED;
1058 
1059 	if (waveOutWrite(cyd->hWaveOut, &cyd->waveout_hdr[cyd->waveout_hdr_idx], sizeof(cyd->waveout_hdr[cyd->waveout_hdr_idx])) != MMSYSERR_NOERROR)
1060 		warning("waveOutWrite returned error");
1061 
1062 	if (++cyd->waveout_hdr_idx >= CYD_NUM_WO_BUFFERS)
1063 		cyd->waveout_hdr_idx = 0;
1064 }
1065 
1066 
ThreadProc(void * param)1067 static DWORD WINAPI ThreadProc(void *param)
1068 {
1069 	CydEngine *cyd = param;
1070 
1071 	for(;;)
1072 	{
1073 		EnterCriticalSection(&cyd->thread_lock);
1074 
1075 		if (!cyd->thread_running)
1076 		{
1077 			LeaveCriticalSection(&cyd->thread_lock);
1078 			break;
1079 		}
1080 
1081 		while (cyd->buffers_available > 0)
1082 		{
1083 			LeaveCriticalSection(&cyd->thread_lock);
1084 			fill_buffer(cyd);
1085 			EnterCriticalSection(&cyd->thread_lock);
1086 			--cyd->buffers_available;
1087 
1088 		}
1089 
1090 		LeaveCriticalSection(&cyd->thread_lock);
1091 
1092 		Sleep(1);
1093 	}
1094 
1095 	debug("Thread exit");
1096 
1097 	return 0;
1098 }
1099 
1100 
waveOutProc(void * param)1101 static DWORD WINAPI waveOutProc(void *param)
1102 {
1103 	CydEngine *cyd = (void*)param;
1104 	MSG msg;
1105 
1106 	while (GetMessage(&msg, 0, 0, 0) == 1)
1107 	{
1108 		if (msg.message == MM_WOM_DONE)
1109 		{
1110 			EnterCriticalSection(&cyd->thread_lock);
1111 
1112 			++cyd->buffers_available;
1113 
1114 			LeaveCriticalSection(&cyd->thread_lock);
1115 		}
1116 
1117 		if (msg.message == MM_WOM_CLOSE)
1118 		{
1119 			break;
1120 		}
1121 	}
1122 
1123 	return 0;
1124 }
1125 
1126 # endif
1127 #endif
1128 
1129 
1130 #ifdef NOSDL_MIXER
cyd_register(CydEngine * cyd,int buffer_length)1131 int cyd_register(CydEngine * cyd, int buffer_length)
1132 #else
1133 int cyd_register(CydEngine * cyd)
1134 #endif
1135 {
1136 #ifndef USENATIVEAPIS
1137 # ifndef NOSDL_MIXER
1138 	int frequency, channels;
1139 	Uint16 format;
1140 	if (Mix_QuerySpec(&frequency, &format, &channels))
1141 	{
1142 		switch (format)
1143 		{
1144 			case AUDIO_S16SYS:
1145 			break;
1146 
1147 			default:
1148 			return 0;
1149 			break;
1150 		}
1151 
1152 		switch (channels)
1153 		{
1154 			case 1: if (!Mix_RegisterEffect(MIX_CHANNEL_POST, cyd_output_buffer, NULL, cyd)) return 0; break;
1155 			case 2: if (!Mix_RegisterEffect(MIX_CHANNEL_POST, cyd_output_buffer_stereo, NULL, cyd)) return 0; break;
1156 			default: return 0; break;
1157 		}
1158 
1159 		return 1;
1160 	}
1161 	else return 0;
1162 # else
1163 
1164 	SDL_AudioSpec desired, obtained;
1165 
1166 	/* 22050Hz - FM Radio quality */
1167 	desired.freq=cyd->sample_rate;
1168 
1169 	/* 16-bit signed audio */
1170 	desired.format=AUDIO_S16SYS;
1171 
1172 	/* Stereo */
1173 	desired.channels=2;
1174 
1175 	/* Large audio buffer reduces risk of dropouts but increases response time */
1176 	desired.samples=buffer_length;
1177 
1178 	/* Our callback function */
1179 	desired.callback=cyd_output_buffer_stereo;
1180 	desired.userdata=cyd;
1181 
1182 	debug("Opening SDL audio");
1183 
1184 	/* Open the audio device */
1185 	if ( SDL_OpenAudio(&desired, &obtained) < 0 )
1186 	{
1187 		warning("Could not open audio device");
1188 		return 0;
1189 	}
1190 
1191 	debug("Got %d Hz/format %d/%d channels", obtained.freq, obtained.format, obtained.channels);
1192 
1193 	SDL_PauseAudio(0);
1194 
1195 	return 1;
1196 # endif
1197 #else
1198 
1199 # ifdef WIN32
1200 	WAVEFORMATEX waveformat;
1201 	waveformat.cbSize = 0;
1202 	waveformat.wFormatTag = WAVE_FORMAT_PCM;
1203     waveformat.wBitsPerSample = 16;
1204 	waveformat.nChannels = 2;
1205     waveformat.nSamplesPerSec = cyd->sample_rate;
1206 	waveformat.nBlockAlign = waveformat.nChannels * waveformat.wBitsPerSample / 8;
1207     waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign;
1208 
1209 	CreateThread(NULL, 0, waveOutProc, cyd, 0, &cyd->cb_handle);
1210 
1211 	MMRESULT result = waveOutOpen(&cyd->hWaveOut, 0, &waveformat, cyd->cb_handle, (DWORD)cyd, CALLBACK_THREAD);
1212 
1213 	if (result != MMSYSERR_NOERROR)
1214 	{
1215 		warning("waveOutOpen failed (%x)", result);
1216 		return 0;
1217 	}
1218 
1219 	for (int i = 0 ; i < CYD_NUM_WO_BUFFERS ; ++i)
1220 	{
1221 		WAVEHDR * h = &cyd->waveout_hdr[i];
1222 
1223 		ZeroMemory(h, sizeof(*h));
1224 
1225 		h->dwBufferLength = CYD_NUM_WO_BUFFER_SIZE * 2 * sizeof(Sint16);
1226 		h->lpData = calloc(h->dwBufferLength, 1);
1227 
1228 		waveOutPrepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[i],sizeof(WAVEHDR));
1229 	}
1230 
1231 	cyd->buffers_available = CYD_NUM_WO_BUFFERS;
1232 	cyd->thread_running = 1;
1233 
1234 	CreateThread(NULL, 0, ThreadProc, cyd, 0, &cyd->thread_handle);
1235 	SetThreadPriority((HANDLE)cyd->thread_handle, THREAD_PRIORITY_HIGHEST);
1236 
1237 	return 1;
1238 # else
1239 
1240 # error Platform not supported for native apis
1241 
1242 # endif
1243 
1244 	return 0;
1245 #endif
1246 }
1247 
1248 
cyd_unregister(CydEngine * cyd)1249 int cyd_unregister(CydEngine * cyd)
1250 {
1251 	debug("cyd_unregister");
1252 #ifndef USENATIVEAPIS
1253 # ifndef NOSDL_MIXER
1254 	int frequency, channels;
1255 	Uint16 format;
1256 	if (Mix_QuerySpec(&frequency, &format, &channels))
1257 	{
1258 		switch (channels)
1259 		{
1260 			case 1: if (!Mix_UnregisterEffect(MIX_CHANNEL_POST, cyd_output_buffer)) return 0; break;
1261 			case 2: if (!Mix_UnregisterEffect(MIX_CHANNEL_POST, cyd_output_buffer_stereo)) return 0; break;
1262 			default: return 0; break;
1263 		}
1264 
1265 		cyd_lock(cyd, 1);
1266 		cyd_lock(cyd, 0);
1267 
1268 		return 1;
1269 	}
1270 	else return 0;
1271 # else
1272 
1273 	debug("Waiting for stuff");
1274 	cyd_lock(cyd, 1);
1275 	debug("Done waiting");
1276 	cyd_lock(cyd, 0);
1277 
1278 	debug("Closing audio");
1279 	SDL_CloseAudio();
1280 	debug("SDL_CloseAudio finished");
1281 
1282 	return 1;
1283 # endif
1284 #else
1285 
1286 	cyd_pause(cyd, 0);
1287 
1288 	debug("Waiting for thread");
1289 	cyd_lock(cyd, 1);
1290 	cyd->thread_running = 0;
1291 	cyd_lock(cyd, 0);
1292 	WaitForSingleObject((HANDLE)cyd->thread_handle, 2000);
1293 
1294 	waveOutReset(cyd->hWaveOut);
1295 
1296 	for (int i = 0 ; i < CYD_NUM_WO_BUFFERS ; ++i)
1297 	{
1298 		if (cyd->waveout_hdr[i].dwFlags & WHDR_PREPARED)
1299 			waveOutUnprepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[i], sizeof(cyd->waveout_hdr[i]));
1300 		free(cyd->waveout_hdr[i].lpData);
1301 	}
1302 
1303 	waveOutClose(cyd->hWaveOut);
1304 
1305 	WaitForSingleObject((HANDLE)cyd->cb_handle, 2000);
1306 
1307 	return 1;
1308 #endif
1309 }
1310 
1311 
cyd_set_filter_coeffs(CydEngine * cyd,CydChannel * chn,Uint16 cutoff,Uint8 resonance)1312 void cyd_set_filter_coeffs(CydEngine * cyd, CydChannel *chn, Uint16 cutoff, Uint8 resonance)
1313 {
1314 #ifndef CYD_DISABLE_FILTER
1315 	static const Uint16 resonance_table[] = {10, 512, 1300, 1950};
1316 	cydflt_set_coeff(&chn->flt, cutoff, resonance_table[resonance & 3]);
1317 #endif
1318 }
1319 
1320 
cyd_lock(CydEngine * cyd,Uint8 enable)1321 void cyd_lock(CydEngine *cyd, Uint8 enable)
1322 {
1323 	if (cyd->flags & CYD_SINGLE_THREAD) return; // For export, mainly
1324 
1325 #ifndef USENATIVEAPIS
1326 
1327 #ifndef USESDLMUTEXES
1328 	if (enable)
1329 	{
1330 #ifdef DEBUG
1331 		Uint32 waittime = SDL_GetTicks();
1332 #endif
1333 		cyd->lock_request = 1;
1334 		while (cyd->lock_locked )
1335 		{
1336 #ifdef DEBUG
1337 			if (SDL_GetTicks() - waittime > 5000)
1338 			{
1339 				warning("Deadlock from cyd_lock");
1340 				waittime = SDL_GetTicks();
1341 			}
1342 #endif
1343 			SDL_Delay(1);
1344 		}
1345 	}
1346 	else
1347 	{
1348 		cyd->lock_request = 0;
1349 		while (cyd->lock_locked)
1350 		{
1351 			SDL_Delay(1);
1352 		}
1353 	}
1354 #else
1355 	if (enable)
1356 	{
1357 		SDL_LockMutex(cyd->mutex);
1358 	}
1359 	else
1360 	{
1361 		SDL_UnlockMutex(cyd->mutex);
1362 	}
1363 #endif
1364 #else
1365 
1366 # ifdef WIN32
1367 	if (enable)
1368 	{
1369 		EnterCriticalSection(&cyd->mutex);
1370 	}
1371 	else
1372 	{
1373 		LeaveCriticalSection(&cyd->mutex);
1374 	}
1375 # endif
1376 
1377 #endif
1378 }
1379 
1380 
1381 #ifdef STEREOOUTPUT
cyd_set_panning(CydEngine * cyd,CydChannel * chn,Uint8 panning)1382 void cyd_set_panning(CydEngine *cyd, CydChannel *chn, Uint8 panning)
1383 {
1384 	if (chn->panning == panning) return;
1385 
1386 	chn->panning = my_min(CYD_PAN_RIGHT, my_max(CYD_PAN_LEFT, panning));
1387 	float a = M_PI / 2 * (float)(chn->panning - CYD_PAN_LEFT) / (CYD_PAN_RIGHT - CYD_PAN_LEFT);
1388 	chn->gain_left = cos(a) * CYD_STEREO_GAIN;
1389 	chn->gain_right = sin(a) * CYD_STEREO_GAIN;
1390 }
1391 #endif
1392 
1393 
cyd_set_wave_entry(CydChannel * chn,const CydWavetableEntry * entry)1394 void cyd_set_wave_entry(CydChannel *chn, const CydWavetableEntry * entry)
1395 {
1396 	chn->wave_entry = entry;
1397 
1398 	for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
1399 	{
1400 		chn->subosc[s].wave.playing = true;
1401 		chn->subosc[s].wave.acc = 0;
1402 		chn->subosc[s].wave.frequency = 0;
1403 		chn->subosc[s].wave.direction = 0;
1404 	}
1405 }
1406 
1407 
cyd_set_wavetable_offset(CydChannel * chn,Uint16 offset)1408 void cyd_set_wavetable_offset(CydChannel *chn, Uint16 offset /* 0..0x1000 = 0-100% */)
1409 {
1410 #ifndef CYD_DISABLE_WAVETABLE
1411 	if (chn->wave_entry)
1412 	{
1413 		for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
1414 		{
1415 			chn->subosc[s].wave.acc = (Uint64)offset * WAVETABLE_RESOLUTION * chn->wave_entry->samples / 0x1000;
1416 		}
1417 	}
1418 #endif
1419 }
1420 
1421 
cyd_pause(CydEngine * cyd,Uint8 enable)1422 void cyd_pause(CydEngine *cyd, Uint8 enable)
1423 {
1424 #ifdef USENATIVEAPIS
1425 #ifdef WIN32
1426 
1427 
1428 	if (enable)
1429 		waveOutPause(cyd->hWaveOut);
1430 	else
1431 		waveOutRestart(cyd->hWaveOut);
1432 #endif
1433 #else
1434 	cyd_lock(cyd, 1);
1435 
1436 	if (enable)
1437 		cyd->flags |= CYD_PAUSED;
1438 	else
1439 		cyd->flags &= ~CYD_PAUSED;
1440 
1441 	cyd_lock(cyd, 0);
1442 #endif
1443 }
1444