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