1 /*
2 Copyright (c) 2009-2010 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 #define GENERATE_VIBRATO_TABLES
27
28 #include "music.h"
29 #include <assert.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include "freqs.h"
34 #include "macros.h"
35 #include "pack.h"
36
37 #ifdef GENERATE_VIBRATO_TABLES
38
39 #include <math.h>
40
41 #endif
42
43 #define VIB_TAB_SIZE 128
44
45 #ifndef GENERATE_VIBRATO_TABLES
46
47 static const Sint8 rnd_table[VIB_TAB_SIZE] = {
48 110, -1, 88, -31, 64,
49 -13, 29, -70, -113, 71,
50 99, -71, 74, 82, 52,
51 -82, -58, 37, 20, -76,
52 46, -97, -69, 41, 31,
53 -62, -5, 99, -2, -48,
54 -89, 17, -19, 4, -27,
55 -43, -20, 25, 112, -34,
56 78, 26, -56, -54, 72,
57 -75, 22, 72, -119, 115,
58 56, -66, 25, 87, 93,
59 14, 82, 127, 79, -40,
60 -100, 21, 17, 17, -116,
61 -110, 61, -99, 105, 73,
62 116, 53, -9, 105, 91,
63 120, -73, 112, -10, 66,
64 -10, -30, 99, -67, 60,
65 84, 110, 87, -27, -46,
66 114, 77, -27, -46, 75,
67 -78, 83, -110, 92, -9,
68 107, -64, 31, 77, -39,
69 115, 126, -7, 121, -2,
70 66, 116, -45, 91, 1,
71 -96, -27, 17, 76, -82,
72 58, -7, 75, -35, 49,
73 3, -52, 40
74 };
75
76 static const Sint8 sine_table[VIB_TAB_SIZE] =
77 {
78 0, 6, 12, 18, 24, 31, 37, 43, 48, 54, 60, 65, 71, 76, 81, 85, 90, 94, 98, 102, 106, 109, 112,
79 115, 118, 120, 122, 124, 125, 126, 127, 127, 127, 127, 127, 126, 125, 124, 122, 120, 118, 115, 112,
80 109, 106, 102, 98, 94, 90, 85, 81, 76, 71, 65, 60, 54, 48, 43, 37, 31, 24, 18, 12, 6,
81 0, -6, -12, -18, -24, -31, -37, -43, -48, -54, -60, -65, -71, -76, -81, -85, -90, -94, -98, -102,
82 -106, -109, -112, -115, -118, -120, -122, -124, -125, -126, -127, -127, -128, -127, -127, -126, -125, -124, -122,
83 -120, -118, -115, -112, -109, -106, -102, -98, -94, -90, -85, -81, -76, -71, -65, -60, -54, -48, -43, -37, -31, -24, -18, -12, -6
84 };
85
86 #else
87
88 static Sint8 rnd_table[VIB_TAB_SIZE];
89 static Sint8 sine_table[VIB_TAB_SIZE];
90
91 #endif
92
93 static int mus_trigger_instrument_internal(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning);
94
95 #ifndef USESDL_RWOPS
96
RWread(struct RWops * context,void * ptr,int size,int maxnum)97 static int RWread(struct RWops *context, void *ptr, int size, int maxnum)
98 {
99 return fread(ptr, size, maxnum, context->fp);
100 }
101
102
RWclose(struct RWops * context)103 static int RWclose(struct RWops *context)
104 {
105 if (context->close_fp) fclose(context->fp);
106 free(context);
107 return 1;
108 }
109
110
111 #define my_RWread(ctx, ptr, size, maxnum) ctx->read(ctx, ptr, size, maxnum)
112 #define my_RWclose(ctx) ctx->close(ctx)
113 #define my_RWtell(ctx) 0
114
115
116 #else
117
118 #include "SDL_rwops.h"
119
120 #define my_RWread SDL_RWread
121 #define my_RWclose SDL_RWclose
122 #define my_RWtell SDL_RWtell
123
124
125 #endif
126
127
RWFromFP(FILE * f,int close)128 static RWops * RWFromFP(FILE *f, int close)
129 {
130 #ifdef USESDL_RWOPS
131 SDL_RWops *rw = SDL_RWFromFP(f, close);
132
133 if (!rw)
134 {
135 warning("SDL_RWFromFP: %s", SDL_GetError());
136 }
137
138 return rw;
139 #else
140 RWops *rw = calloc(sizeof(*rw), 1);
141
142 rw->fp = f;
143 rw->close_fp = close;
144 rw->read = RWread;
145 rw->close = RWclose;
146
147 return rw;
148 #endif
149 }
150
151
RWFromFile(const char * name,const char * mode)152 static RWops * RWFromFile(const char *name, const char *mode)
153 {
154 #ifdef USESDL_RWOPS
155 return SDL_RWFromFile(name, mode);
156 #else
157 FILE *f = fopen(name, mode);
158
159 if (!f) return NULL;
160
161 return RWFromFP(f, 1);
162 #endif
163 }
164
165
166
update_volumes(MusEngine * mus,MusTrackStatus * ts,MusChannel * chn,CydChannel * cydchn,int volume)167 static void update_volumes(MusEngine *mus, MusTrackStatus *ts, MusChannel *chn, CydChannel *cydchn, int volume)
168 {
169 if (chn->instrument && (chn->instrument->flags & MUS_INST_RELATIVE_VOLUME))
170 {
171 ts->volume = volume;
172 cydchn->adsr.volume = (chn->flags & MUS_CHN_DISABLED) ? 0 : (int)chn->instrument->volume * volume / MAX_VOLUME * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)chn->volume / MAX_VOLUME;
173 }
174 else
175 {
176 ts->volume = volume;
177 cydchn->adsr.volume = (chn->flags & MUS_CHN_DISABLED) ? 0 : ts->volume * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)chn->volume / MAX_VOLUME;
178 }
179 }
180
181
update_all_volumes(MusEngine * mus)182 static void update_all_volumes(MusEngine *mus)
183 {
184 for (int i = 0 ; i < MUS_MAX_CHANNELS && i < mus->cyd->n_channels ; ++i)
185 update_volumes(mus, &mus->song_track[i], &mus->channel[i], &mus->cyd->channel[i], mus->song_track[i].volume);
186 }
187
188
mus_set_buzz_frequency(MusEngine * mus,int chan,Uint16 note)189 static void mus_set_buzz_frequency(MusEngine *mus, int chan, Uint16 note)
190 {
191 #ifndef CYD_DISABLE_BUZZ
192 MusChannel *chn = &mus->channel[chan];
193 if (chn->instrument && chn->instrument->flags & MUS_INST_YM_BUZZ)
194 {
195 #ifndef CYD_DISABLE_INACCURACY
196 Uint16 buzz_frequency = get_freq(note + chn->buzz_offset) & mus->pitch_mask;
197 #else
198 Uint16 buzz_frequency = get_freq(note + chn->buzz_offset);
199 #endif
200 cyd_set_env_frequency(mus->cyd, &mus->cyd->channel[chan], buzz_frequency);
201 }
202 #endif
203 }
204
205
mus_set_wavetable_frequency(MusEngine * mus,int chan,Uint16 note)206 static void mus_set_wavetable_frequency(MusEngine *mus, int chan, Uint16 note)
207 {
208 #ifndef CYD_DISABLE_WAVETABLE
209 MusChannel *chn = &mus->channel[chan];
210 CydChannel *cydchn = &mus->cyd->channel[chan];
211 MusTrackStatus *track_status = &mus->song_track[chan];
212
213 if (chn->instrument && (chn->instrument->cydflags & CYD_CHN_ENABLE_WAVE) && (cydchn->wave_entry))
214 {
215 for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
216 {
217 Uint16 final = 0;
218
219 if (s == 0 || (chn->instrument->flags & MUS_INST_MULTIOSC))
220 {
221 switch (s)
222 {
223 default:
224 case 0:
225 final = note;
226 break;
227
228 case 1:
229 if (track_status->extarp1 != 0)
230 final = note + ((Uint16)track_status->extarp1 << 8);
231 else
232 final = 0;
233 break;
234
235 case 2:
236 if (track_status->extarp2 != 0)
237 final = note + ((Uint16)track_status->extarp2 << 8);
238 else
239 final = 0;
240 break;
241 }
242 }
243
244 Uint16 wave_frequency = 0;
245
246 if (final != 0)
247 {
248 #ifndef CYD_DISABLE_INACCURACY
249 wave_frequency = get_freq((chn->instrument->flags & MUS_INST_WAVE_LOCK_NOTE) ? cydchn->wave_entry->base_note : (final)) & mus->pitch_mask;
250 #else
251 wave_frequency = get_freq((chn->instrument->flags & MUS_INST_WAVE_LOCK_NOTE) ? cydchn->wave_entry->base_note : (final));
252 #endif
253 }
254
255 cyd_set_wavetable_frequency(mus->cyd, cydchn, s, wave_frequency);
256 }
257 }
258 #endif
259 }
260
261
mus_set_frequency(MusEngine * mus,int chan,Uint16 note,int divider)262 static void mus_set_frequency(MusEngine *mus, int chan, Uint16 note, int divider)
263 {
264 MusChannel *chn = &mus->channel[chan];
265 MusTrackStatus *track_status = &mus->song_track[chan];
266
267 for (int s = 0 ; s < CYD_SUB_OSCS ; ++s)
268 {
269 Uint16 final = 0;
270
271 if (s == 0 || (chn->instrument->flags & MUS_INST_MULTIOSC))
272 {
273 switch (s)
274 {
275 default:
276 case 0:
277 final = note;
278 break;
279
280 case 1:
281 if (track_status->extarp1 != 0)
282 final = note + ((Uint16)track_status->extarp1 << 8);
283 else
284 final = 0;
285 break;
286
287 case 2:
288 if (track_status->extarp2 != 0)
289 final = note + ((Uint16)track_status->extarp2 << 8);
290 else
291 final = 0;
292 break;
293 }
294 }
295
296 Uint16 frequency = 0;
297
298 if (final != 0)
299 {
300 #ifndef CYD_DISABLE_INACCURACY
301 frequency = get_freq(final) & mus->pitch_mask;
302 #else
303 frequency = get_freq(final);
304 #endif
305 }
306
307 cyd_set_frequency(mus->cyd, &mus->cyd->channel[chan], s, frequency / divider);
308 }
309 }
310
311
mus_set_note(MusEngine * mus,int chan,Uint16 note,int update_note,int divider)312 static void mus_set_note(MusEngine *mus, int chan, Uint16 note, int update_note, int divider)
313 {
314 MusChannel *chn = &mus->channel[chan];
315
316 if (update_note) chn->note = note;
317
318 mus_set_frequency(mus, chan, note, divider);
319
320 mus_set_wavetable_frequency(mus, chan, note);
321
322 mus_set_buzz_frequency(mus, chan, note);
323 }
324
325
mus_set_slide(MusEngine * mus,int chan,Uint16 note)326 static void mus_set_slide(MusEngine *mus, int chan, Uint16 note)
327 {
328 MusChannel *chn = &mus->channel[chan];
329 chn->target_note = note;
330 //if (update_note) chn->note = note;
331 }
332
333
mus_init_engine(MusEngine * mus,CydEngine * cyd)334 void mus_init_engine(MusEngine *mus, CydEngine *cyd)
335 {
336 memset(mus, 0, sizeof(*mus));
337 mus->cyd = cyd;
338 mus->volume = MAX_VOLUME;
339 mus->play_volume = MAX_VOLUME;
340
341 for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
342 mus->channel[i].volume = MAX_VOLUME;
343
344 #ifndef CYD_DISABLE_INACCURACY
345 mus->pitch_mask = ~0;
346 #endif
347
348 #ifdef GENERATE_VIBRATO_TABLES
349 for (int i = 0 ; i < VIB_TAB_SIZE ; ++i)
350 {
351 sine_table[i] = sin((float)i / VIB_TAB_SIZE * M_PI * 2) * 127;
352 rnd_table[i] = rand();
353 }
354 #endif
355 }
356
357
do_command(MusEngine * mus,int chan,int tick,Uint16 inst,int from_program)358 static void do_command(MusEngine *mus, int chan, int tick, Uint16 inst, int from_program)
359 {
360 MusChannel *chn = &mus->channel[chan];
361 CydChannel *cydchn = &mus->cyd->channel[chan];
362 CydEngine *cyd = mus->cyd;
363 MusTrackStatus *track_status = &mus->song_track[chan];
364
365 switch (inst & 0x7f00)
366 {
367 case MUS_FX_PORTA_UP:
368 {
369 Uint16 prev = chn->note;
370 chn->note += ((inst & 0xff) << 2);
371 if (prev > chn->note) chn->note = 0xffff;
372
373 mus_set_slide(mus, chan, chn->note);
374 }
375 break;
376
377 case MUS_FX_PORTA_DN:
378 {
379 Uint16 prev = chn->note;
380 chn->note -= ((inst & 0xff) << 2);
381
382 if (prev < chn->note) chn->note = 0x0;
383
384 mus_set_slide(mus, chan, chn->note);
385 }
386 break;
387
388 case MUS_FX_PORTA_UP_LOG:
389 {
390 Uint16 prev = chn->note;
391 chn->note += my_max(1, ((Uint32)frequency_table[MIDDLE_C] * (Uint32)(inst & 0xff) / (Uint32)get_freq(chn->note)));
392
393 if (prev > chn->note) chn->note = 0xffff;
394
395 mus_set_slide(mus, chan, chn->note);
396 }
397 break;
398
399 case MUS_FX_PORTA_DN_LOG:
400 {
401 Uint16 prev = chn->note;
402 chn->note -= my_max(1, ((Uint32)frequency_table[MIDDLE_C] * (Uint32)(inst & 0xff) / (Uint32)get_freq(chn->note)));
403
404 if (prev < chn->note) chn->note = 0x0;
405
406 mus_set_slide(mus, chan, chn->note);
407 }
408 break;
409
410 case MUS_FX_PW_DN:
411 {
412 track_status->pw -= inst & 0xff;
413 if (track_status->pw > 0xf000) track_status->pw = 0;
414 }
415 break;
416
417 case MUS_FX_PW_UP:
418 {
419 track_status->pw += inst & 0xff;
420 if (track_status->pw > 0x7ff) track_status->pw = 0x7ff;
421 }
422 break;
423
424 #ifndef CYD_DISABLE_FILTER
425 case MUS_FX_CUTOFF_DN:
426 {
427 track_status->filter_cutoff -= inst & 0xff;
428 if (track_status->filter_cutoff > 0xf000) track_status->filter_cutoff = 0;
429 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance);
430 }
431 break;
432
433 case MUS_FX_CUTOFF_UP:
434 {
435 track_status->filter_cutoff += inst & 0xff;
436 if (track_status->filter_cutoff > 0x7ff) track_status->filter_cutoff = 0x7ff;
437 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance);
438 }
439 break;
440 #endif
441
442 #ifndef CYD_DISABLE_BUZZ
443 case MUS_FX_BUZZ_DN:
444 {
445 if (chn->buzz_offset >= -32768 + (inst & 0xff))
446 chn->buzz_offset -= inst & 0xff;
447
448 mus_set_buzz_frequency(mus, chan, chn->note);
449 }
450 break;
451
452 case MUS_FX_BUZZ_UP:
453 {
454 if (chn->buzz_offset <= 32767 - (inst & 0xff))
455 chn->buzz_offset += inst & 0xff;
456
457 mus_set_buzz_frequency(mus, chan, chn->note);
458 }
459 break;
460 #endif
461 case MUS_FX_TRIGGER_RELEASE:
462 {
463 if (tick == (inst & 0xff))
464 cyd_enable_gate(mus->cyd, cydchn, 0);
465 }
466 break;
467
468 case MUS_FX_FADE_VOLUME:
469 {
470 if (!(chn->flags & MUS_CHN_DISABLED))
471 {
472 track_status->volume -= inst & 0xf;
473 if (track_status->volume > MAX_VOLUME) track_status->volume = 0;
474 track_status->volume += (inst >> 4) & 0xf;
475 if (track_status->volume > MAX_VOLUME) track_status->volume = MAX_VOLUME;
476
477 update_volumes(mus, track_status, chn, cydchn, track_status->volume);
478 }
479 }
480 break;
481 #ifdef STEREOOUTPUT
482 case MUS_FX_PAN_RIGHT:
483 case MUS_FX_PAN_LEFT:
484 {
485 int p = cydchn->panning;
486 if ((inst & 0xff00) == MUS_FX_PAN_LEFT)
487 {
488 p -= inst & 0x00ff;
489 }
490 else
491 {
492 p += inst & 0x00ff;
493 }
494
495 p = my_min(CYD_PAN_RIGHT, my_max(CYD_PAN_LEFT, p));
496
497 cyd_set_panning(mus->cyd, cydchn, p);
498 }
499 break;
500 #endif
501 case MUS_FX_EXT:
502 {
503 // Protracker style Exy commands
504
505 switch (inst & 0xfff0)
506 {
507 case MUS_FX_EXT_NOTE_CUT:
508 {
509 if (!(chn->flags & MUS_CHN_DISABLED))
510 {
511 if ((inst & 0xf) <= tick)
512 {
513 cydchn->adsr.volume = 0;
514 track_status->volume = 0;
515 }
516 }
517 }
518 break;
519
520 case MUS_FX_EXT_RETRIGGER:
521 {
522 if ((inst & 0xf) > 0 && (tick % (inst & 0xf)) == 0)
523 {
524 Uint8 prev_vol_tr = track_status->volume;
525 Uint8 prev_vol_cyd = cydchn->adsr.volume;
526 mus_trigger_instrument_internal(mus, chan, chn->instrument, chn->last_note, -1);
527 track_status->volume = prev_vol_tr;
528 cydchn->adsr.volume = prev_vol_cyd;
529 }
530 }
531 break;
532 }
533 }
534 break;
535 }
536
537 if (tick == 0)
538 {
539 // --- commands that run only on tick 0
540
541 switch (inst & 0xff00)
542 {
543 case MUS_FX_EXT:
544 {
545 // Protracker style Exy commands
546
547 switch (inst & 0xfff0)
548 {
549 case MUS_FX_EXT_FADE_VOLUME_DN:
550 {
551 if (!(chn->flags & MUS_CHN_DISABLED))
552 {
553 track_status->volume -= inst & 0xf;
554 if (track_status->volume > MAX_VOLUME) track_status->volume = 0;
555
556 update_volumes(mus, track_status, chn, cydchn, track_status->volume);
557 }
558 }
559 break;
560
561 case MUS_FX_EXT_FADE_VOLUME_UP:
562 {
563 if (!(chn->flags & MUS_CHN_DISABLED))
564 {
565 track_status->volume += inst & 0xf;
566 if (track_status->volume > MAX_VOLUME) track_status->volume = MAX_VOLUME;
567
568 update_volumes(mus, track_status, chn, cydchn, track_status->volume);
569 }
570 }
571 break;
572
573 case MUS_FX_EXT_PORTA_UP:
574 {
575 Uint16 prev = chn->note;
576 chn->note += ((inst & 0x0f));
577
578 if (prev > chn->note) chn->note = 0xffff;
579
580 mus_set_slide(mus, chan, chn->note);
581 }
582 break;
583
584 case MUS_FX_EXT_PORTA_DN:
585 {
586 Uint16 prev = chn->note;
587 chn->note -= ((inst & 0x0f));
588
589 if (prev < chn->note) chn->note = 0x0;
590
591 mus_set_slide(mus, chan, chn->note);
592 }
593 break;
594 }
595 }
596 break;
597
598 default:
599
600 switch (inst & 0xf000)
601 {
602 #ifndef CYD_DISABLE_FILTER
603 case MUS_FX_CUTOFF_FINE_SET:
604 {
605 track_status->filter_cutoff = (inst & 0xfff);
606 if (track_status->filter_cutoff > 0x7ff) track_status->filter_cutoff = 0x7ff;
607 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance);
608 }
609 break;
610 #endif
611
612 #ifndef CYD_DISABLE_WAVETABLE
613 case MUS_FX_WAVETABLE_OFFSET:
614 {
615 cyd_set_wavetable_offset(cydchn, inst & 0xfff);
616 }
617 break;
618 #endif
619 }
620
621 switch (inst & 0x7f00)
622 {
623 case MUS_FX_SET_GLOBAL_VOLUME:
624 {
625 mus->play_volume = my_min((inst & 0xff), MAX_VOLUME);
626
627 update_all_volumes(mus);
628 }
629 break;
630
631 case MUS_FX_FADE_GLOBAL_VOLUME:
632 {
633 mus->play_volume -= inst & 0xf;
634
635 if (mus->play_volume > MAX_VOLUME) mus->play_volume = 0;
636
637 mus->play_volume += (inst & 0xf0) >> 4;
638
639 if (mus->play_volume > MAX_VOLUME) mus->play_volume = MAX_VOLUME;
640
641 update_all_volumes(mus);
642 }
643 break;
644
645 case MUS_FX_SET_CHANNEL_VOLUME:
646 {
647 chn->volume = my_min((inst & 0xff), MAX_VOLUME);
648 update_volumes(mus, track_status, chn, cydchn, track_status->volume);
649 }
650 break;
651
652 case MUS_FX_PW_SET:
653 {
654 track_status->pw = (inst & 0xff) << 4;
655 }
656 break;
657 #ifndef CYD_DISABLE_BUZZ
658 case MUS_FX_BUZZ_SHAPE:
659 {
660 cyd_set_env_shape(cydchn, inst & 3);
661 }
662 break;
663
664 case MUS_FX_BUZZ_SET_SEMI:
665 {
666 chn->buzz_offset = (((inst & 0xff)) - 0x80) << 8;
667
668 mus_set_buzz_frequency(mus, chan, chn->note);
669 }
670 break;
671
672 case MUS_FX_BUZZ_SET:
673 {
674 chn->buzz_offset = (chn->buzz_offset & 0xff00) | (inst & 0xff);
675
676 mus_set_buzz_frequency(mus, chan, chn->note);
677 }
678 break;
679 #endif
680
681 #ifndef CYD_DISABLE_FM
682 case MUS_FX_FM_SET_MODULATION:
683 {
684 cydchn->fm.adsr.volume = inst % MAX_VOLUME;
685 }
686 break;
687
688 case MUS_FX_FM_SET_HARMONIC:
689 {
690 cydchn->fm.harmonic = inst % 256;
691 }
692 break;
693
694 case MUS_FX_FM_SET_FEEDBACK:
695 {
696 cydchn->fm.feedback = inst % 8;
697 }
698 break;
699
700 case MUS_FX_FM_SET_WAVEFORM:
701 {
702 if ((inst & 255) < CYD_WAVE_MAX_ENTRIES)
703 {
704 cydchn->fm.wave_entry = &mus->cyd->wavetable_entries[inst & 255];
705 }
706 }
707 break;
708 #endif
709
710 #ifdef STEREOOUTPUT
711 case MUS_FX_SET_PANNING:
712 {
713 cyd_set_panning(mus->cyd, cydchn, inst & 0xff);
714 }
715 break;
716 #endif
717
718 #ifndef CYD_DISABLE_FILTER
719 case MUS_FX_FILTER_TYPE:
720 {
721 cydchn->flttype = (inst & 0xf) % FLT_TYPES;
722 }
723 break;
724
725 case MUS_FX_CUTOFF_SET:
726 {
727 track_status->filter_cutoff = (inst & 0xff) << 3;
728 if (track_status->filter_cutoff > 0x7ff) track_status->filter_cutoff = 0x7ff;
729 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance);
730 }
731 break;
732
733 case MUS_FX_CUTOFF_SET_COMBINED:
734 {
735 if ((inst & 0xff) < 0x80)
736 {
737 track_status->filter_cutoff = (inst & 0xff) << 4;
738 cydchn->flttype = FLT_LP;
739 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance);
740 }
741 else
742 {
743 track_status->filter_cutoff = ((inst & 0xff) - 0x80) << 4;
744 cydchn->flttype = FLT_HP;
745 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance);
746 }
747 }
748 break;
749
750 case MUS_FX_RESONANCE_SET:
751 {
752 track_status->filter_resonance = inst & 3;
753 cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, inst & 3);
754 }
755 break;
756 #endif
757
758 case MUS_FX_SET_SPEED:
759 {
760 if (from_program)
761 {
762 chn->prog_period = inst & 0xff;
763 }
764 else
765 {
766 mus->song->song_speed = inst & 0xf;
767 if ((inst & 0xf0) == 0) mus->song->song_speed2 = mus->song->song_speed;
768 else mus->song->song_speed2 = (inst >> 4) & 0xf;
769 }
770 }
771 break;
772
773 case MUS_FX_SET_RATE:
774 {
775 mus->song->song_rate = inst & 0xff;
776 if (mus->song->song_rate < 1) mus->song->song_rate = 1;
777 cyd_set_callback_rate(mus->cyd, mus->song->song_rate);
778 }
779 break;
780
781 case MUS_FX_PORTA_UP_SEMI:
782 {
783 Uint16 prev = chn->note;
784 chn->note += (inst&0xff) << 8;
785 if (prev > chn->note || chn->note >= (FREQ_TAB_SIZE << 8)) chn->note = ((FREQ_TAB_SIZE-1) << 8);
786 mus_set_slide(mus, chan, chn->note);
787 }
788 break;
789
790 case MUS_FX_PORTA_DN_SEMI:
791 {
792 Uint16 prev = chn->note;
793 chn->note -= (inst&0xff) << 8;
794 if (prev < chn->note) chn->note = 0x0;
795 mus_set_slide(mus, chan, chn->note);
796 }
797 break;
798
799 case MUS_FX_ARPEGGIO_ABS:
800 {
801 chn->arpeggio_note = 0;
802 chn->fixed_note = (inst & 0xff) << 8;
803 }
804 break;
805
806 case MUS_FX_ARPEGGIO:
807 {
808 if (chn->fixed_note != 0xffff)
809 {
810 chn->note = chn->last_note;
811 chn->fixed_note = 0xffff;
812 }
813
814 if ((inst & 0xff) == 0xf0)
815 chn->arpeggio_note = track_status->extarp1;
816 else if ((inst & 0xff) == 0xf1)
817 chn->arpeggio_note = track_status->extarp2;
818 else
819 chn->arpeggio_note = inst & 0xff;
820 }
821 break;
822
823 case MUS_FX_SET_VOLUME:
824 {
825 track_status->volume = my_min(MAX_VOLUME, inst & 0xff);
826
827 update_volumes(mus, track_status, chn, cydchn, track_status->volume);
828 }
829 break;
830
831 case MUS_FX_SET_SYNCSRC:
832 {
833 if ((inst & 0xff) != 0xff)
834 {
835 cydchn->sync_source = (inst & 0xff) % CYD_MAX_FX_CHANNELS;
836 cydchn->flags |= CYD_CHN_ENABLE_SYNC;
837 }
838 else
839 cydchn->flags &= ~CYD_CHN_ENABLE_SYNC;
840 }
841 break;
842
843 case MUS_FX_SET_RINGSRC:
844 {
845 if ((inst & 0xff) != 0xff)
846 {
847 cydchn->ring_mod = (inst & 0xff) % CYD_MAX_FX_CHANNELS;
848 cydchn->flags |= CYD_CHN_ENABLE_RING_MODULATION;
849 }
850 else
851 cydchn->flags &= ~CYD_CHN_ENABLE_RING_MODULATION;
852 }
853 break;
854
855 #ifndef CYD_DISABLE_FX
856 case MUS_FX_SET_FXBUS:
857 {
858 cydchn->fx_bus = (inst & 0xff) % CYD_MAX_FX_CHANNELS;
859 }
860 break;
861
862 case MUS_FX_SET_DOWNSAMPLE:
863 {
864 cydcrush_set(&cyd->fx[cydchn->fx_bus].crush, inst & 0xff, -1, -1, -1);
865 }
866 break;
867 #endif
868
869 #ifndef CYD_DISABLE_WAVETABLE
870 case MUS_FX_SET_WAVETABLE_ITEM:
871 {
872 if ((inst & 255) < CYD_WAVE_MAX_ENTRIES)
873 {
874 cydchn->wave_entry = &mus->cyd->wavetable_entries[inst & 255];
875 }
876 }
877 break;
878 #endif
879
880 case MUS_FX_SET_WAVEFORM:
881 {
882 int final = 0;
883
884 if (inst & MUS_FX_WAVE_NOISE)
885 final |= CYD_CHN_ENABLE_NOISE;
886
887 if (inst & MUS_FX_WAVE_PULSE)
888 final |= CYD_CHN_ENABLE_PULSE;
889
890 if (inst & MUS_FX_WAVE_TRIANGLE)
891 final |= CYD_CHN_ENABLE_TRIANGLE;
892
893 if (inst & MUS_FX_WAVE_SAW)
894 final |= CYD_CHN_ENABLE_SAW;
895
896 if (inst & MUS_FX_WAVE_WAVE)
897 final |= CYD_CHN_ENABLE_WAVE;
898
899 #ifndef CYD_DISABLE_LFSR
900 if (inst & MUS_FX_WAVE_LFSR)
901 final |= CYD_CHN_ENABLE_LFSR;
902 #endif
903
904 cyd_set_waveform(cydchn, final);
905 }
906 break;
907
908 case MUS_FX_RESTART_PROGRAM:
909 {
910 if (!from_program)
911 {
912 chn->program_counter = 0;
913 chn->program_tick = 0;
914 chn->program_loop = 1;
915 }
916 }
917 break;
918 }
919
920 break;
921 }
922 }
923 }
924
925
mus_exec_track_command(MusEngine * mus,int chan,int first_tick)926 static void mus_exec_track_command(MusEngine *mus, int chan, int first_tick)
927 {
928 MusTrackStatus *track_status = &mus->song_track[chan];
929 const Uint16 inst = track_status->pattern->step[track_status->pattern_step].command;
930 const Uint8 vol = track_status->pattern->step[track_status->pattern_step].volume;
931
932 switch (vol & 0xf0)
933 {
934 case MUS_NOTE_VOLUME_PAN_LEFT:
935 do_command(mus, chan, mus->song_counter, MUS_FX_PAN_LEFT | ((Uint16)(vol & 0xf)), 0);
936 break;
937
938 case MUS_NOTE_VOLUME_PAN_RIGHT:
939 do_command(mus, chan, mus->song_counter, MUS_FX_PAN_RIGHT | ((Uint16)(vol & 0xf)), 0);
940 break;
941
942 case MUS_NOTE_VOLUME_SET_PAN:
943 {
944 Uint16 val = vol & 0xf;
945 Uint16 panning = (val <= 8 ? val * CYD_PAN_CENTER / 8 : (val - 8) * (CYD_PAN_RIGHT - CYD_PAN_CENTER) / 8 + CYD_PAN_CENTER);
946 do_command(mus, chan, mus->song_counter, MUS_FX_SET_PANNING | panning, 0);
947 debug("Panned to %x", panning);
948 }
949 break;
950
951 case MUS_NOTE_VOLUME_FADE_UP:
952 do_command(mus, chan, mus->song_counter, MUS_FX_FADE_VOLUME | ((Uint16)(vol & 0xf) << 4), 0);
953 break;
954
955 case MUS_NOTE_VOLUME_FADE_DN:
956 do_command(mus, chan, mus->song_counter, MUS_FX_FADE_VOLUME | ((Uint16)(vol & 0xf)), 0);
957 break;
958
959 default:
960 if (vol <= MAX_VOLUME)
961 do_command(mus, chan, first_tick ? 0 : mus->song_counter, MUS_FX_SET_VOLUME | (Uint16)(vol), 0);
962 break;
963 }
964
965 switch (inst & 0xff00)
966 {
967 case MUS_FX_ARPEGGIO:
968 if (!(inst & 0xff)) break; // no params = use the same settings
969 case MUS_FX_SET_EXT_ARP:
970 {
971 track_status->extarp1 = (inst & 0xf0) >> 4;
972 track_status->extarp2 = (inst & 0xf);
973 }
974 break;
975
976 default:
977 do_command(mus, chan, mus->song_counter, inst, 0);
978 break;
979 }
980 }
981
982
mus_exec_prog_tick(MusEngine * mus,int chan,int advance)983 static void mus_exec_prog_tick(MusEngine *mus, int chan, int advance)
984 {
985 MusChannel *chn = &mus->channel[chan];
986 int tick = chn->program_tick;
987 int visited[MUS_PROG_LEN] = { 0 };
988
989 do_it_again:;
990
991 const Uint16 inst = chn->instrument->program[tick];
992
993 switch (inst)
994 {
995 case MUS_FX_END:
996 {
997 chn->flags &= ~MUS_CHN_PROGRAM_RUNNING;
998 return;
999 }
1000 break;
1001 }
1002
1003 int dont_reloop = 0;
1004
1005 if(inst != MUS_FX_NOP)
1006 {
1007 switch (inst & 0xff00)
1008 {
1009 case MUS_FX_JUMP:
1010 {
1011 /* This should handle infinite jumping between two jump instructions (program hang) */
1012
1013 if (!visited[tick])
1014 {
1015 visited[tick] = 1;
1016 tick = inst & (MUS_PROG_LEN - 1);
1017 }
1018 else return;
1019 }
1020 break;
1021
1022 case MUS_FX_LABEL:
1023 {
1024
1025
1026 }
1027 break;
1028
1029 case MUS_FX_LOOP:
1030 {
1031 if (chn->program_loop == (inst & 0xff))
1032 {
1033 if (advance) chn->program_loop = 1;
1034 }
1035 else
1036 {
1037 if (advance) ++chn->program_loop;
1038
1039 int l = 0;
1040
1041 while ((chn->instrument->program[tick] & 0xff00) != MUS_FX_LABEL && tick > 0)
1042 {
1043 --tick;
1044 if (!(chn->instrument->program[tick] & 0x8000)) ++l;
1045 }
1046
1047 --tick;
1048
1049 dont_reloop = l <= 1;
1050 }
1051 }
1052 break;
1053
1054 default:
1055
1056 do_command(mus, chan, chn->program_counter, inst, 1);
1057
1058 break;
1059 }
1060 }
1061
1062 if (inst == MUS_FX_NOP || (inst & 0xff00) != MUS_FX_JUMP)
1063 {
1064 ++tick;
1065 if (tick >= MUS_PROG_LEN)
1066 {
1067 tick = 0;
1068 }
1069 }
1070
1071 // skip to next on msb
1072
1073 if ((inst & 0x8000) && inst != MUS_FX_NOP && !dont_reloop)
1074 {
1075 goto do_it_again;
1076 }
1077
1078 if (advance)
1079 {
1080 chn->program_tick = tick;
1081 }
1082 }
1083
mus_shape(Uint16 position,Uint8 shape)1084 static Sint8 mus_shape(Uint16 position, Uint8 shape)
1085 {
1086 switch (shape)
1087 {
1088 case MUS_SHAPE_SINE:
1089 return sine_table[position % VIB_TAB_SIZE];
1090 break;
1091
1092 case MUS_SHAPE_SQUARE:
1093 return ((position % VIB_TAB_SIZE) & (VIB_TAB_SIZE / 2)) ? -128 : 127;
1094 break;
1095
1096 case MUS_SHAPE_RAMP_UP:
1097 return (position % VIB_TAB_SIZE) * 2 - 128;
1098 break;
1099
1100 case MUS_SHAPE_RAMP_DN:
1101 return 127 - (position % VIB_TAB_SIZE) * 2;
1102 break;
1103
1104 default:
1105 case MUS_SHAPE_RANDOM:
1106 return rnd_table[(position / 8) % VIB_TAB_SIZE];
1107 break;
1108 }
1109 }
1110
1111
1112 #ifndef CYD_DISABLE_PWM
1113
do_pwm(MusEngine * mus,int chan)1114 static void do_pwm(MusEngine* mus, int chan)
1115 {
1116 MusChannel *chn = &mus->channel[chan];
1117 MusInstrument *ins = chn->instrument;
1118 MusTrackStatus *track_status = &mus->song_track[chan];
1119
1120 track_status->pwm_position += ins->pwm_speed;
1121 mus->cyd->channel[chan].pw = track_status->pw + mus_shape(track_status->pwm_position >> 1, ins->pwm_shape) * ins->pwm_depth / 32;
1122 }
1123
1124 #endif
1125
1126
1127 //***** USE THIS INSIDE MUS_ADVANCE_TICK TO AVOID MUTEX DEADLOCK
mus_trigger_instrument_internal(MusEngine * mus,int chan,MusInstrument * ins,Uint16 note,int panning)1128 int mus_trigger_instrument_internal(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning)
1129 {
1130 if (chan == -1)
1131 {
1132 for (int i = 0 ; i < mus->cyd->n_channels ; ++i)
1133 {
1134 if (!(mus->cyd->channel[i].flags & CYD_CHN_ENABLE_GATE))
1135 chan = i;
1136 }
1137
1138 if (chan == -1)
1139 chan = (rand() % mus->cyd->n_channels);
1140 }
1141
1142 CydChannel *cydchn = &mus->cyd->channel[chan];
1143 MusChannel *chn = &mus->channel[chan];
1144 MusTrackStatus *track = &mus->song_track[chan];
1145
1146 chn->flags = MUS_CHN_PLAYING | (chn->flags & MUS_CHN_DISABLED);
1147 if (ins->prog_period > 0) chn->flags |= MUS_CHN_PROGRAM_RUNNING;
1148 chn->prog_period = ins->prog_period;
1149 chn->instrument = ins;
1150 if (!(ins->flags & MUS_INST_NO_PROG_RESTART))
1151 {
1152 chn->program_counter = 0;
1153 chn->program_tick = 0;
1154 chn->program_loop = 1;
1155 }
1156 cydchn->flags = ins->cydflags;
1157 chn->arpeggio_note = 0;
1158 chn->fixed_note = 0xffff;
1159 cydchn->fx_bus = ins->fx_bus;
1160
1161 if (ins->flags & MUS_INST_DRUM)
1162 {
1163 cyd_set_waveform(cydchn, CYD_CHN_ENABLE_NOISE);
1164 }
1165
1166 if (ins->flags & MUS_INST_LOCK_NOTE)
1167 {
1168 note = ((Uint16)ins->base_note) << 8;
1169 }
1170 else
1171 {
1172 note += (Uint16)((int)ins->base_note-MIDDLE_C) << 8;
1173 }
1174
1175 mus_set_note(mus, chan, ((Uint16)note) + ins->finetune, 1, ins->flags & MUS_INST_QUARTER_FREQ ? 4 : 1);
1176 chn->last_note = chn->target_note = (((Uint16)note) + ins->finetune);
1177 chn->current_tick = 0;
1178
1179 track->vibrato_position = 0;
1180 track->vib_delay = ins->vib_delay;
1181
1182 track->slide_speed = 0;
1183
1184 update_volumes(mus, track, chn, cydchn, (ins->flags & MUS_INST_RELATIVE_VOLUME) ? MAX_VOLUME : ins->volume);
1185
1186 cydchn->sync_source = ins->sync_source == 0xff? chan : ins->sync_source;
1187 cydchn->ring_mod = ins->ring_mod == 0xff? chan : ins->ring_mod;
1188
1189 if (cydchn->ring_mod >= mus->cyd->n_channels)
1190 cydchn->ring_mod = mus->cyd->n_channels -1;
1191
1192 if (cydchn->sync_source >= mus->cyd->n_channels)
1193 cydchn->sync_source = mus->cyd->n_channels -1;
1194
1195 cydchn->flttype = ins->flttype;
1196 cydchn->lfsr_type = ins->lfsr_type;
1197
1198 if (ins->cydflags & CYD_CHN_ENABLE_KEY_SYNC)
1199 {
1200 track->pwm_position = 0;
1201 }
1202
1203 #ifndef CYD_DISABLE_FILTER
1204 if (ins->flags & MUS_INST_SET_CUTOFF)
1205 {
1206 track->filter_cutoff = ins->cutoff;
1207 track->filter_resonance = ins->resonance;
1208 cyd_set_filter_coeffs(mus->cyd, cydchn, ins->cutoff, ins->resonance);
1209 }
1210 #endif
1211
1212 if (ins->flags & MUS_INST_SET_PW)
1213 {
1214 track->pw = ins->pw;
1215 #ifndef CYD_DISABLE_PWM
1216 do_pwm(mus,chan);
1217 #endif
1218 }
1219
1220 if (ins->flags & MUS_INST_YM_BUZZ)
1221 {
1222 #ifndef CYD_DISABLE_BUZZ
1223 cydchn->flags |= CYD_CHN_ENABLE_YM_ENV;
1224 cyd_set_env_shape(cydchn, ins->ym_env_shape);
1225 mus->channel[chan].buzz_offset = ins->buzz_offset;
1226 #endif
1227 }
1228 else
1229 {
1230 cydchn->flags &= ~CYD_CHN_ENABLE_YM_ENV;
1231
1232
1233 cydchn->adsr.a = ins->adsr.a;
1234 cydchn->adsr.d = ins->adsr.d;
1235 cydchn->adsr.s = ins->adsr.s;
1236 cydchn->adsr.r = ins->adsr.r;
1237 }
1238
1239 #ifndef CYD_DISABLE_WAVETABLE
1240 if (ins->cydflags & CYD_CHN_ENABLE_WAVE)
1241 {
1242 cyd_set_wave_entry(cydchn, &mus->cyd->wavetable_entries[ins->wavetable_entry]);
1243 }
1244 else
1245 {
1246 cyd_set_wave_entry(cydchn, NULL);
1247 }
1248
1249 #ifndef CYD_DISABLE_FM
1250 if (ins->fm_flags & CYD_FM_ENABLE_WAVE)
1251 {
1252 cydfm_set_wave_entry(&cydchn->fm, &mus->cyd->wavetable_entries[ins->fm_wave]);
1253 }
1254 else
1255 {
1256 cydfm_set_wave_entry(&cydchn->fm, NULL);
1257 }
1258 #endif
1259 #endif
1260
1261 #ifdef STEREOOUTPUT
1262 if (panning != -1)
1263 cyd_set_panning(mus->cyd, cydchn, panning);
1264
1265 #endif
1266
1267 #ifndef CYD_DISABLE_FM
1268 CydFm *fm = &cydchn->fm;
1269
1270 fm->flags = ins->fm_flags;
1271 fm->harmonic = ins->fm_harmonic;
1272 fm->adsr.a = ins->fm_adsr.a;
1273 fm->adsr.d = ins->fm_adsr.d;
1274 fm->adsr.s = ins->fm_adsr.s;
1275 fm->adsr.r = ins->fm_adsr.r;
1276 fm->adsr.volume = ins->fm_modulation;
1277 fm->feedback = ins->fm_feedback;
1278 fm->attack_start = ins->fm_attack_start;
1279 #endif
1280
1281 //cyd_set_frequency(mus->cyd, cydchn, chn->frequency);
1282 cyd_enable_gate(mus->cyd, cydchn, 1);
1283
1284 return chan;
1285 }
1286
1287
mus_trigger_instrument(MusEngine * mus,int chan,MusInstrument * ins,Uint16 note,int panning)1288 int mus_trigger_instrument(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning)
1289 {
1290 cyd_lock(mus->cyd, 1);
1291
1292 chan = mus_trigger_instrument_internal(mus, chan, ins, note, panning);
1293
1294 cyd_lock(mus->cyd, 0);
1295
1296 return chan;
1297 }
1298
1299
mus_advance_channel(MusEngine * mus,int chan)1300 static void mus_advance_channel(MusEngine* mus, int chan)
1301 {
1302 MusChannel *chn = &mus->channel[chan];
1303 MusTrackStatus *track_status = &mus->song_track[chan];
1304
1305 if (!(mus->cyd->channel[chan].flags & CYD_CHN_ENABLE_GATE))
1306 {
1307 chn->flags &= ~MUS_CHN_PLAYING;
1308 return;
1309 }
1310
1311 MusInstrument *ins = chn->instrument;
1312
1313 if (ins->flags & MUS_INST_DRUM && chn->current_tick == 1)
1314 {
1315 cyd_set_waveform(&mus->cyd->channel[chan], ins->cydflags);
1316 }
1317
1318 if (track_status->slide_speed != 0)
1319 {
1320 if (chn->target_note > chn->note)
1321 {
1322 chn->note += my_min((Uint16)track_status->slide_speed, chn->target_note - chn->note);
1323 }
1324 else if (chn->target_note < chn->note)
1325 {
1326 chn->note -= my_min((Uint16)track_status->slide_speed , chn->note - chn->target_note);
1327 }
1328 }
1329
1330 ++chn->current_tick;
1331
1332 if (mus->channel[chan].flags & MUS_CHN_PROGRAM_RUNNING)
1333 {
1334 int u = (chn->program_counter + 1) >= chn->prog_period;
1335 mus_exec_prog_tick(mus, chan, u);
1336 ++chn->program_counter;
1337 if (u) chn->program_counter = 0;
1338
1339 /*++chn->program_counter;
1340 if (chn->program_counter >= chn->instrument->prog_period)
1341 {
1342 ++chn->program_tick;
1343
1344 if (chn->program_tick >= MUS_PROG_LEN)
1345 {
1346 chn->program_tick = 0;
1347 }
1348 chn->program_counter = 0;
1349 }*/
1350 }
1351
1352 #ifndef CYD_DISABLE_VIBRATO
1353
1354 Uint8 ctrl = 0;
1355 int vibdep = my_max(0, (int)ins->vibrato_depth - (int)track_status->vib_delay);
1356 int vibspd = ins->vibrato_speed;
1357
1358 if (track_status->pattern)
1359 {
1360 ctrl = track_status->pattern->step[track_status->pattern_step].ctrl;
1361 if ((track_status->pattern->step[track_status->pattern_step].command & 0xff00) == MUS_FX_VIBRATO)
1362 {
1363 ctrl |= MUS_CTRL_VIB;
1364 if (track_status->pattern->step[track_status->pattern_step].command & 0xff)
1365 {
1366 vibdep = (track_status->pattern->step[track_status->pattern_step].command & 0xf) << 2;
1367 vibspd = (track_status->pattern->step[track_status->pattern_step].command & 0xf0) >> 2;
1368
1369 if (!vibspd)
1370 vibspd = ins->vibrato_speed;
1371 if (!vibdep)
1372 vibdep = ins->vibrato_depth;
1373 }
1374 }
1375
1376 /*do_vib(mus, chan, track_status->pattern->step[track_status->pattern_step].ctrl);
1377
1378 if ((track_status->last_ctrl & MUS_CTRL_VIB) && !(track_status->pattern->step[track_status->pattern_step].ctrl & MUS_CTRL_VIB))
1379 {
1380 cyd_set_frequency(mus->cyd, &mus->cyd->channel[chan], mus->channel[chan].frequency);
1381 }
1382
1383 track_status->last_ctrl = track_status->pattern->step[track_status->pattern_step].ctrl;*/
1384 }
1385
1386 #endif
1387
1388 Sint16 vib = 0;
1389
1390 #ifndef CYD_DISABLE_VIBRATO
1391 if (((ctrl & MUS_CTRL_VIB) && !(ins->flags & MUS_INST_INVERT_VIBRATO_BIT)) || (!(ctrl & MUS_CTRL_VIB) && (ins->flags & MUS_INST_INVERT_VIBRATO_BIT)))
1392 {
1393 track_status->vibrato_position += vibspd;
1394 vib = mus_shape(track_status->vibrato_position >> 1, ins->vib_shape) * vibdep / 64;
1395 if (track_status->vib_delay) --track_status->vib_delay;
1396 }
1397 #endif
1398
1399 #ifndef CYD_DISABLE_PWM
1400 do_pwm(mus, chan);
1401 #endif
1402
1403 Sint32 note = (mus->channel[chan].fixed_note != 0xffff ? mus->channel[chan].fixed_note : mus->channel[chan].note) + vib + ((Uint16)mus->channel[chan].arpeggio_note << 8);
1404
1405 if (note < 0) note = 0;
1406 if (note > FREQ_TAB_SIZE << 8) note = (FREQ_TAB_SIZE - 1) << 8;
1407
1408 mus_set_note(mus, chan, note, 0, ins->flags & MUS_INST_QUARTER_FREQ ? 4 : 1);
1409 }
1410
1411
mus_ext_sync(MusEngine * mus)1412 Uint32 mus_ext_sync(MusEngine *mus)
1413 {
1414 cyd_lock(mus->cyd, 1);
1415
1416 Uint32 s = ++mus->ext_sync_ticks;
1417
1418 cyd_lock(mus->cyd, 0);
1419
1420 return s;
1421 }
1422
1423
mus_advance_tick(void * udata)1424 int mus_advance_tick(void* udata)
1425 {
1426 MusEngine *mus = udata;
1427
1428 if (!(mus->flags & MUS_EXT_SYNC))
1429 mus->ext_sync_ticks = 1;
1430
1431 while (mus->ext_sync_ticks-- > 0)
1432 {
1433 if (mus->song)
1434 {
1435 for (int i = 0 ; i < mus->song->num_channels ; ++i)
1436 {
1437 MusTrackStatus *track_status = &mus->song_track[i];
1438 CydChannel *cydchn = &mus->cyd->channel[i];
1439 MusChannel *muschn = &mus->channel[i];
1440
1441 if (mus->song_counter == 0)
1442 {
1443 while (track_status->sequence_position < mus->song->num_sequences[i] && mus->song->sequence[i][track_status->sequence_position].position <= mus->song_position)
1444 {
1445 track_status->pattern = &mus->song->pattern[mus->song->sequence[i][track_status->sequence_position].pattern];
1446 track_status->pattern_step = mus->song_position - mus->song->sequence[i][track_status->sequence_position].position;
1447 if (track_status->pattern_step >= mus->song->pattern[mus->song->sequence[i][track_status->sequence_position].pattern].num_steps)
1448 track_status->pattern = NULL;
1449 track_status->note_offset = mus->song->sequence[i][track_status->sequence_position].note_offset;
1450 ++track_status->sequence_position;
1451 }
1452 }
1453
1454 int delay = 0;
1455
1456 if (track_status->pattern)
1457 {
1458 if ((track_status->pattern->step[track_status->pattern_step].command & 0x7FF0) == MUS_FX_EXT_NOTE_DELAY)
1459 delay = track_status->pattern->step[track_status->pattern_step].command & 0xf;
1460 }
1461
1462 if (mus->song_counter == delay)
1463 {
1464 if (track_status->pattern)
1465 {
1466
1467 if (1 || track_status->pattern_step == 0)
1468 {
1469 Uint8 note = track_status->pattern->step[track_status->pattern_step].note < 0xf0 ?
1470 track_status->pattern->step[track_status->pattern_step].note + track_status->note_offset :
1471 track_status->pattern->step[track_status->pattern_step].note;
1472 Uint8 inst = track_status->pattern->step[track_status->pattern_step].instrument;
1473 MusInstrument *pinst = NULL;
1474
1475 if (inst == MUS_NOTE_NO_INSTRUMENT)
1476 {
1477 pinst = muschn->instrument;
1478 }
1479 else
1480 {
1481 if (inst < mus->song->num_instruments)
1482 {
1483 pinst = &mus->song->instrument[inst];
1484 muschn->instrument = pinst;
1485 }
1486 }
1487
1488 if (note == MUS_NOTE_RELEASE)
1489 {
1490 cyd_enable_gate(mus->cyd, &mus->cyd->channel[i], 0);
1491 }
1492 else if (pinst && note != MUS_NOTE_NONE)
1493 {
1494 track_status->slide_speed = 0;
1495 int speed = pinst->slide_speed | 1;
1496 Uint8 ctrl = track_status->pattern->step[track_status->pattern_step].ctrl;
1497
1498 if ((track_status->pattern->step[track_status->pattern_step].command & 0xff00) == MUS_FX_SLIDE)
1499 {
1500 ctrl |= MUS_CTRL_SLIDE | MUS_CTRL_LEGATO;
1501 speed = (track_status->pattern->step[track_status->pattern_step].command & 0xff);
1502 }
1503
1504 if (ctrl & MUS_CTRL_SLIDE)
1505 {
1506 if (ctrl & MUS_CTRL_LEGATO)
1507 {
1508 mus_set_slide(mus, i, (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune);
1509 }
1510 else
1511 {
1512 Uint16 oldnote = muschn->note;
1513 mus_trigger_instrument_internal(mus, i, pinst, note << 8, -1);
1514 muschn->note = oldnote;
1515 }
1516 track_status->slide_speed = speed;
1517 }
1518 else if (ctrl & MUS_CTRL_LEGATO)
1519 {
1520 mus_set_note(mus, i, (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune, 1, pinst->flags & MUS_INST_QUARTER_FREQ ? 4 : 1);
1521 muschn->target_note = (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune;
1522 }
1523 else
1524 {
1525 Uint8 prev_vol_track = track_status->volume;
1526 Uint8 prev_vol_cyd = cydchn->adsr.volume;
1527 mus_trigger_instrument_internal(mus, i, pinst, note << 8, -1);
1528 muschn->target_note = (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune;
1529
1530 if (inst == MUS_NOTE_NO_INSTRUMENT)
1531 {
1532 track_status->volume = prev_vol_track;
1533 cydchn->adsr.volume = prev_vol_cyd;
1534 }
1535 }
1536
1537 if (inst != MUS_NOTE_NO_INSTRUMENT)
1538 {
1539 if (pinst->flags & MUS_INST_RELATIVE_VOLUME)
1540 {
1541 track_status->volume = MAX_VOLUME;
1542 cydchn->adsr.volume = (muschn->flags & MUS_CHN_DISABLED)
1543 ? 0
1544 : (int)pinst->volume * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)muschn->volume / MAX_VOLUME;
1545 }
1546 else
1547 {
1548 track_status->volume = pinst->volume;
1549 cydchn->adsr.volume = (muschn->flags & MUS_CHN_DISABLED) ? 0 : (int)pinst->volume * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)muschn->volume / MAX_VOLUME;
1550 }
1551 }
1552 }
1553 }
1554 }
1555 }
1556
1557 if (track_status->pattern) mus_exec_track_command(mus, i, mus->song_counter == delay);
1558 }
1559
1560 ++mus->song_counter;
1561 if (mus->song_counter >= ((!(mus->song_position & 1)) ? mus->song->song_speed : mus->song->song_speed2))
1562 {
1563 for (int i = 0 ; i < mus->cyd->n_channels ; ++i)
1564 {
1565 MusTrackStatus *track_status = &mus->song_track[i];
1566
1567 if (track_status->pattern)
1568 {
1569 Uint32 command = track_status->pattern->step[track_status->pattern_step].command;
1570 if ((command & 0xff00) == MUS_FX_LOOP_PATTERN)
1571 {
1572 Uint16 step = command & 0xff;
1573 track_status->pattern_step = step;
1574 }
1575 else if ((command & 0xff00) == MUS_FX_SKIP_PATTERN)
1576 {
1577 mus->song_position += my_max(track_status->pattern->num_steps - track_status->pattern_step - 1, 0);
1578 track_status->pattern = NULL;
1579 track_status->pattern_step = 0;
1580 }
1581 else
1582 {
1583 ++track_status->pattern_step;
1584 }
1585
1586 if (track_status->pattern && track_status->pattern_step >= track_status->pattern->num_steps)
1587 {
1588 track_status->pattern = NULL;
1589 track_status->pattern_step = 0;
1590 }
1591 }
1592 }
1593 mus->song_counter = 0;
1594 ++mus->song_position;
1595 if (mus->song_position >= mus->song->song_length)
1596 {
1597 if (mus->song->flags & MUS_NO_REPEAT)
1598 return 0;
1599
1600 mus->song_position = mus->song->loop_point;
1601 for (int i = 0 ; i < mus->cyd->n_channels ; ++i)
1602 {
1603 MusTrackStatus *track_status = &mus->song_track[i];
1604
1605 track_status->pattern = NULL;
1606 track_status->pattern_step = 0;
1607 track_status->sequence_position = 0;
1608 }
1609 }
1610 }
1611 }
1612
1613 for (int i = 0 ; i < mus->cyd->n_channels ; ++i)
1614 {
1615 if (mus->channel[i].flags & MUS_CHN_PLAYING)
1616 {
1617 mus_advance_channel(mus, i);
1618 }
1619 }
1620
1621 #ifndef CYD_DISABLE_MULTIPLEX
1622 if (mus->song && (mus->song->flags & MUS_ENABLE_MULTIPLEX) && mus->song->multiplex_period > 0)
1623 {
1624 for (int i = 0 ; i < mus->cyd->n_channels ; ++i)
1625 {
1626 CydChannel *cydchn = &mus->cyd->channel[i];
1627
1628 if ((mus->multiplex_ctr / mus->song->multiplex_period) == i)
1629 {
1630 update_volumes(mus, &mus->song_track[i], &mus->channel[i], cydchn, mus->song_track[i].volume);
1631 }
1632 else
1633 {
1634 cydchn->adsr.volume = 0;
1635 }
1636 }
1637
1638 if (++mus->multiplex_ctr >= mus->song->num_channels * mus->song->multiplex_period)
1639 mus->multiplex_ctr = 0;
1640 }
1641 #endif
1642 }
1643
1644 return 1;
1645 }
1646
1647
mus_set_song(MusEngine * mus,MusSong * song,Uint16 position)1648 void mus_set_song(MusEngine *mus, MusSong *song, Uint16 position)
1649 {
1650 cyd_lock(mus->cyd, 1);
1651 cyd_reset(mus->cyd);
1652 mus->song = song;
1653
1654 if (song != NULL)
1655 {
1656 mus->song_counter = 0;
1657 mus->multiplex_ctr = 0;
1658 #ifndef CYD_DISABLE_INACCURACY
1659 mus->pitch_mask = (~0) << song->pitch_inaccuracy;
1660 #endif
1661 }
1662
1663 mus->song_position = position;
1664 mus->play_volume = MAX_VOLUME;
1665
1666 for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
1667 {
1668 mus->song_track[i].pattern = NULL;
1669 mus->song_track[i].pattern_step = 0;
1670 mus->song_track[i].sequence_position = 0;
1671 mus->song_track[i].last_ctrl = 0;
1672 mus->song_track[i].note_offset = 0;
1673 mus->song_track[i].extarp1 = mus->song_track[i].extarp2 = 0;
1674
1675 if (song)
1676 {
1677 mus->channel[i].volume = song->default_volume[i];
1678 #ifdef STEREOOUTPUT
1679 if (i < mus->cyd->n_channels)
1680 cyd_set_panning(mus->cyd, &mus->cyd->channel[i], song->default_panning[i] + CYD_PAN_CENTER);
1681 #endif
1682 }
1683 else
1684 {
1685 mus->channel[i].volume = MAX_VOLUME;
1686 }
1687 }
1688
1689 cyd_lock(mus->cyd, 0);
1690 }
1691
1692
mus_poll_status(MusEngine * mus,int * song_position,int * pattern_position,MusPattern ** pattern,MusChannel * channel,int * cyd_env,int * mus_note,Uint64 * time_played)1693 int mus_poll_status(MusEngine *mus, int *song_position, int *pattern_position, MusPattern **pattern, MusChannel *channel, int *cyd_env, int *mus_note, Uint64 *time_played)
1694 {
1695 cyd_lock(mus->cyd, 1);
1696
1697 if (song_position) *song_position = mus->song_position;
1698
1699 if (pattern_position)
1700 {
1701 for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
1702 {
1703 pattern_position[i] = mus->song_track[i].pattern_step;
1704 }
1705 }
1706
1707 if (pattern)
1708 {
1709 for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
1710 {
1711 pattern[i] = mus->song_track[i].pattern;
1712 }
1713 }
1714
1715 if (channel)
1716 {
1717 memcpy(channel, mus->channel, sizeof(mus->channel));
1718 }
1719
1720 if (cyd_env)
1721 {
1722 for (int i = 0 ; i < my_min(mus->cyd->n_channels, MUS_MAX_CHANNELS) ; ++i)
1723 {
1724 if (mus->cyd->channel[i].flags & CYD_CHN_ENABLE_YM_ENV)
1725 cyd_env[i] = mus->cyd->channel[i].adsr.volume;
1726 else
1727 cyd_env[i] = cyd_env_output(mus->cyd, mus->cyd->channel[i].flags, &mus->cyd->channel[i].adsr, MAX_VOLUME);
1728 }
1729 }
1730
1731 if (mus_note)
1732 {
1733 for (int i = 0 ; i < my_min(mus->cyd->n_channels, MUS_MAX_CHANNELS) ; ++i)
1734 {
1735 mus_note[i] = mus->channel[i].note;
1736 }
1737 }
1738
1739 if (time_played)
1740 {
1741 *time_played = mus->cyd->samples_played * 1000 / mus->cyd->sample_rate;
1742 }
1743
1744 cyd_lock(mus->cyd, 0);
1745
1746 return mus->song != NULL;
1747 }
1748
1749
mus_load_instrument(const char * path,MusInstrument * inst,CydWavetableEntry * wavetable_entries)1750 int mus_load_instrument(const char *path, MusInstrument *inst, CydWavetableEntry *wavetable_entries)
1751 {
1752 RWops *ctx = RWFromFile(path, "rb");
1753
1754 if (ctx)
1755 {
1756 int r = mus_load_instrument_RW2(ctx, inst, wavetable_entries);
1757
1758 my_RWclose(ctx);
1759
1760 return r;
1761 }
1762
1763 return 0;
1764 }
1765
1766
load_wavetable_entry(Uint8 version,CydWavetableEntry * e,RWops * ctx)1767 static void load_wavetable_entry(Uint8 version, CydWavetableEntry * e, RWops *ctx)
1768 {
1769 VER_READ(version, 12, 0xff, &e->flags, 0);
1770 VER_READ(version, 12, 0xff, &e->sample_rate, 0);
1771 VER_READ(version, 12, 0xff, &e->samples, 0);
1772 VER_READ(version, 12, 0xff, &e->loop_begin, 0);
1773 VER_READ(version, 12, 0xff, &e->loop_end, 0);
1774 VER_READ(version, 12, 0xff, &e->base_note, 0);
1775
1776 FIX_ENDIAN(e->flags);
1777 FIX_ENDIAN(e->sample_rate);
1778 FIX_ENDIAN(e->samples);
1779 FIX_ENDIAN(e->loop_begin);
1780 FIX_ENDIAN(e->loop_end);
1781 FIX_ENDIAN(e->base_note);
1782
1783 if (e->samples > 0)
1784 {
1785 if (version < 15)
1786 {
1787 Sint16 *data = malloc(sizeof(data[0]) * e->samples);
1788
1789 my_RWread(ctx, data, sizeof(data[0]), e->samples);
1790
1791 cyd_wave_entry_init(e, data, e->samples, CYD_WAVE_TYPE_SINT16, 1, 1, 1);
1792
1793 free(data);
1794 }
1795 else
1796 {
1797 Uint32 data_size = 0;
1798 VER_READ(version, 15, 0xff, &data_size, 0);
1799 FIX_ENDIAN(data_size);
1800 Uint8 *compressed = malloc(sizeof(Uint8) * data_size);
1801
1802 my_RWread(ctx, compressed, sizeof(Uint8), (data_size + 7) / 8); // data_size is in bits
1803
1804 Sint16 *data = NULL;
1805
1806 #ifndef CYD_DISABLE_WAVETABLE
1807 data = bitunpack(compressed, data_size, e->samples, (e->flags >> 3) & 3);
1808 #endif
1809
1810 if (data)
1811 {
1812 cyd_wave_entry_init(e, data, e->samples, CYD_WAVE_TYPE_SINT16, 1, 1, 1);
1813 free(data);
1814 }
1815 else
1816 {
1817 warning("Sample data unpack failed");
1818 }
1819
1820 free(compressed);
1821 }
1822 }
1823 }
1824
1825
find_and_load_wavetable(Uint8 version,RWops * ctx,CydWavetableEntry * wavetable_entries)1826 static int find_and_load_wavetable(Uint8 version, RWops *ctx, CydWavetableEntry *wavetable_entries)
1827 {
1828 for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i)
1829 {
1830 CydWavetableEntry *e = &wavetable_entries[i];
1831
1832 if (e->samples == 0)
1833 {
1834 load_wavetable_entry(version, e, ctx);
1835 return i;
1836 }
1837 }
1838
1839 return 0;
1840 }
1841
1842
mus_load_instrument_RW(Uint8 version,RWops * ctx,MusInstrument * inst,CydWavetableEntry * wavetable_entries)1843 int mus_load_instrument_RW(Uint8 version, RWops *ctx, MusInstrument *inst, CydWavetableEntry *wavetable_entries)
1844 {
1845 mus_get_default_instrument(inst);
1846
1847 debug("Loading instrument at offset %x", (Uint32)my_RWtell(ctx));
1848
1849 _VER_READ(&inst->flags, 0);
1850 _VER_READ(&inst->cydflags, 0);
1851 _VER_READ(&inst->adsr, 0);
1852 _VER_READ(&inst->sync_source, 0);
1853 _VER_READ(&inst->ring_mod, 0);
1854 _VER_READ(&inst->pw, 0);
1855 _VER_READ(&inst->volume, 0);
1856 Uint8 progsteps = 0;
1857 _VER_READ(&progsteps, 0);
1858 if (progsteps)
1859 _VER_READ(&inst->program, (int)progsteps*sizeof(inst->program[0]));
1860 _VER_READ(&inst->prog_period, 0);
1861 _VER_READ(&inst->vibrato_speed, 0);
1862 _VER_READ(&inst->vibrato_depth, 0);
1863 _VER_READ(&inst->pwm_speed, 0);
1864 _VER_READ(&inst->pwm_depth, 0);
1865 _VER_READ(&inst->slide_speed, 0);
1866 _VER_READ(&inst->base_note, 0);
1867
1868 if (version >= 20)
1869 _VER_READ(&inst->finetune, 0);
1870
1871 Uint8 len = 16;
1872 VER_READ(version, 11, 0xff, &len, 0);
1873 if (len)
1874 {
1875 memset(inst->name, 0, sizeof(inst->name));
1876 _VER_READ(inst->name, my_min(len, sizeof(inst->name)));
1877 inst->name[sizeof(inst->name) - 1] = '\0';
1878 }
1879
1880 VER_READ(version, 1, 0xff, &inst->cutoff, 0);
1881 VER_READ(version, 1, 0xff, &inst->resonance, 0);
1882 VER_READ(version, 1, 0xff, &inst->flttype, 0);
1883 VER_READ(version, 7, 0xff, &inst->ym_env_shape, 0);
1884 VER_READ(version, 7, 0xff, &inst->buzz_offset, 0);
1885 VER_READ(version, 10, 0xff, &inst->fx_bus, 0);
1886 VER_READ(version, 11, 0xff, &inst->vib_shape, 0);
1887 VER_READ(version, 11, 0xff, &inst->vib_delay, 0);
1888 VER_READ(version, 11, 0xff, &inst->pwm_shape, 0);
1889 VER_READ(version, 18, 0xff, &inst->lfsr_type, 0);
1890 VER_READ(version, 12, 0xff, &inst->wavetable_entry, 0);
1891
1892 VER_READ(version, 23, 0xff, &inst->fm_flags, 0);
1893 VER_READ(version, 23, 0xff, &inst->fm_modulation, 0);
1894 VER_READ(version, 23, 0xff, &inst->fm_feedback, 0);
1895 VER_READ(version, 23, 0xff, &inst->fm_harmonic, 0);
1896 VER_READ(version, 23, 0xff, &inst->fm_adsr, 0);
1897 VER_READ(version, 25, 0xff, &inst->fm_attack_start, 0);
1898 VER_READ(version, 23, 0xff, &inst->fm_wave, 0);
1899
1900 #ifndef CYD_DISABLE_WAVETABLE
1901 if (wavetable_entries)
1902 {
1903 if (inst->wavetable_entry == 0xff)
1904 {
1905 inst->wavetable_entry = find_and_load_wavetable(version, ctx, wavetable_entries);
1906 }
1907
1908 if (version >= 23)
1909 {
1910 if (inst->fm_wave == 0xff)
1911 {
1912 inst->fm_wave = find_and_load_wavetable(version, ctx, wavetable_entries);
1913 }
1914 else if (inst->fm_wave == 0xfe)
1915 {
1916 inst->fm_wave = inst->wavetable_entry;
1917 }
1918 }
1919 }
1920 #endif
1921
1922 /* The file format is little-endian, the following only does something on big-endian machines */
1923
1924 FIX_ENDIAN(inst->flags);
1925 FIX_ENDIAN(inst->cydflags);
1926 FIX_ENDIAN(inst->pw);
1927 FIX_ENDIAN(inst->cutoff);
1928 FIX_ENDIAN(inst->buzz_offset);
1929
1930 for (int i = 0 ; i < progsteps ; ++i)
1931 FIX_ENDIAN(inst->program[i]);
1932
1933 FIX_ENDIAN(inst->fm_flags);
1934
1935 if (version < 26)
1936 {
1937 inst->adsr.a *= ENVELOPE_SCALE;
1938 inst->adsr.d *= ENVELOPE_SCALE;
1939 inst->adsr.r *= ENVELOPE_SCALE;
1940
1941 inst->fm_adsr.a *= ENVELOPE_SCALE;
1942 inst->fm_adsr.d *= ENVELOPE_SCALE;
1943 inst->fm_adsr.r *= ENVELOPE_SCALE;
1944 }
1945
1946 return 1;
1947 }
1948
1949
mus_load_instrument_RW2(RWops * ctx,MusInstrument * inst,CydWavetableEntry * wavetable_entries)1950 int mus_load_instrument_RW2(RWops *ctx, MusInstrument *inst, CydWavetableEntry *wavetable_entries)
1951 {
1952 char id[9];
1953
1954 id[8] = '\0';
1955
1956 my_RWread(ctx, id, 8, sizeof(id[0]));
1957
1958 if (strcmp(id, MUS_INST_SIG) == 0)
1959 {
1960 Uint8 version = 0;
1961 my_RWread(ctx, &version, 1, sizeof(version));
1962
1963 if (version > MUS_VERSION)
1964 return 0;
1965
1966 mus_load_instrument_RW(version, ctx, inst, wavetable_entries);
1967
1968 return 1;
1969 }
1970 else
1971 {
1972 debug("Instrument signature does not match");
1973 return 0;
1974 }
1975 }
1976
1977
mus_get_default_instrument(MusInstrument * inst)1978 void mus_get_default_instrument(MusInstrument *inst)
1979 {
1980 memset(inst, 0, sizeof(*inst));
1981 inst->flags = MUS_INST_DRUM|MUS_INST_SET_PW|MUS_INST_SET_CUTOFF;
1982 inst->pw = 0x600;
1983 inst->cydflags = CYD_CHN_ENABLE_TRIANGLE;
1984 inst->adsr.a = 1 * ENVELOPE_SCALE;
1985 inst->adsr.d = 12 * ENVELOPE_SCALE;
1986 inst->volume = MAX_VOLUME;
1987 inst->base_note = MIDDLE_C;
1988 inst->finetune = 0;
1989 inst->prog_period = 2;
1990 inst->cutoff = 2047;
1991 inst->slide_speed = 0x80;
1992 inst->vibrato_speed = 0x20;
1993 inst->vibrato_depth = 0x20;
1994 inst->vib_shape = MUS_SHAPE_SINE;
1995 inst->vib_delay = 0;
1996
1997 for (int p = 0 ; p < MUS_PROG_LEN; ++p)
1998 inst->program[p] = MUS_FX_NOP;
1999 }
2000
2001
mus_set_fx(MusEngine * mus,MusSong * song)2002 void mus_set_fx(MusEngine *mus, MusSong *song)
2003 {
2004 cyd_lock(mus->cyd, 1);
2005 for(int f = 0 ; f < CYD_MAX_FX_CHANNELS ; ++f)
2006 {
2007 cydfx_set(&mus->cyd->fx[f], &song->fx[f]);
2008 }
2009
2010 #ifndef CYD_DISABLE_INACCURACY
2011 mus->pitch_mask = (~0) << song->pitch_inaccuracy;
2012 #endif
2013
2014 cyd_lock(mus->cyd, 0);
2015 }
2016
2017
inner_load_fx(RWops * ctx,CydFxSerialized * fx,int version)2018 static void inner_load_fx(RWops *ctx, CydFxSerialized *fx, int version)
2019 {
2020 Uint8 padding;
2021
2022 debug("fx @ %u", (Uint32)my_RWtell(ctx));
2023
2024 if (version >= 22)
2025 {
2026 Uint8 len = 16;
2027 my_RWread(ctx, &len, 1, 1);
2028 if (len)
2029 {
2030 memset(fx->name, 0, sizeof(fx->name));
2031 _VER_READ(fx->name, my_min(len, sizeof(fx->name)));
2032 fx->name[sizeof(fx->name) - 1] = '\0';
2033 }
2034 }
2035
2036 my_RWread(ctx, &fx->flags, 1, 4);
2037 my_RWread(ctx, &fx->crush.bit_drop, 1, 1);
2038 my_RWread(ctx, &fx->chr.rate, 1, 1);
2039 my_RWread(ctx, &fx->chr.min_delay, 1, 1);
2040 my_RWread(ctx, &fx->chr.max_delay, 1, 1);
2041 my_RWread(ctx, &fx->chr.sep, 1, 1);
2042
2043 Uint8 spread = 0;
2044
2045 if (version < 27)
2046 my_RWread(ctx, &spread, 1, 1);
2047
2048 if (version < 21)
2049 my_RWread(ctx, &padding, 1, 1);
2050
2051 int taps = CYDRVB_TAPS;
2052
2053 if (version < 27)
2054 taps = 8;
2055
2056 for (int i = 0 ; i < taps ; ++i)
2057 {
2058 my_RWread(ctx, &fx->rvb.tap[i].delay, 2, 1);
2059 my_RWread(ctx, &fx->rvb.tap[i].gain, 2, 1);
2060
2061 if (version >= 27)
2062 {
2063 my_RWread(ctx, &fx->rvb.tap[i].panning, 1, 1);
2064 my_RWread(ctx, &fx->rvb.tap[i].flags, 1, 1);
2065 }
2066 else
2067 {
2068 fx->rvb.tap[i].flags = 1;
2069
2070 if (spread > 0)
2071 fx->rvb.tap[i].panning = CYD_PAN_LEFT;
2072 else
2073 fx->rvb.tap[i].panning = CYD_PAN_CENTER;
2074 }
2075
2076 FIX_ENDIAN(fx->rvb.tap[i].gain);
2077 FIX_ENDIAN(fx->rvb.tap[i].delay);
2078 }
2079
2080 if (version < 27)
2081 {
2082 if (spread == 0)
2083 {
2084 for (int i = 8 ; i < CYDRVB_TAPS ; ++i)
2085 {
2086 fx->rvb.tap[i].flags = 0;
2087 fx->rvb.tap[i].delay = 1000;
2088 fx->rvb.tap[i].gain = CYDRVB_LOW_LIMIT;
2089 }
2090 }
2091 else
2092 {
2093 for (int i = 8 ; i < CYDRVB_TAPS ; ++i)
2094 {
2095 fx->rvb.tap[i].flags = 1;
2096 fx->rvb.tap[i].panning = CYD_PAN_RIGHT;
2097 fx->rvb.tap[i].delay = my_min(CYDRVB_SIZE, fx->rvb.tap[i - 8].delay + (fx->rvb.tap[i - 8].delay * spread) / 2000);
2098 fx->rvb.tap[i].gain = fx->rvb.tap[i - 8].gain;
2099 }
2100 }
2101 }
2102
2103 my_RWread(ctx, &fx->crushex.downsample, 1, 1);
2104
2105 if (version < 19)
2106 {
2107 fx->crushex.gain = 128;
2108 }
2109 else
2110 {
2111 my_RWread(ctx, &fx->crushex.gain, 1, 1);
2112 }
2113
2114 FIX_ENDIAN(fx->flags);
2115 }
2116
2117
mus_load_fx_RW(RWops * ctx,CydFxSerialized * fx)2118 int mus_load_fx_RW(RWops *ctx, CydFxSerialized *fx)
2119 {
2120 char id[9];
2121 id[8] = '\0';
2122
2123 my_RWread(ctx, id, 8, sizeof(id[0]));
2124
2125 if (strcmp(id, MUS_FX_SIG) == 0)
2126 {
2127 Uint8 version = 0;
2128 my_RWread(ctx, &version, 1, sizeof(version));
2129
2130 debug("FX version = %u", version);
2131
2132 inner_load_fx(ctx, fx, version);
2133
2134 return 1;
2135 }
2136 else
2137 return 0;
2138 }
2139
2140
mus_load_fx_file(FILE * f,CydFxSerialized * fx)2141 int mus_load_fx_file(FILE *f, CydFxSerialized *fx)
2142 {
2143 RWops *rw = RWFromFP(f, 0);
2144
2145 if (rw)
2146 {
2147 int r = mus_load_fx_RW(rw, fx);
2148
2149 my_RWclose(rw);
2150
2151 return r;
2152 }
2153
2154 return 0;
2155 }
2156
2157
mus_load_fx(const char * path,CydFxSerialized * fx)2158 int mus_load_fx(const char *path, CydFxSerialized *fx)
2159 {
2160 RWops *rw = RWFromFile(path, "rb");
2161
2162 if (rw)
2163 {
2164 int r = mus_load_fx_RW(rw, fx);
2165
2166 my_RWclose(rw);
2167
2168 return r;
2169 }
2170
2171 return 0;
2172 }
2173
2174
mus_load_song_RW(RWops * ctx,MusSong * song,CydWavetableEntry * wavetable_entries)2175 int mus_load_song_RW(RWops *ctx, MusSong *song, CydWavetableEntry *wavetable_entries)
2176 {
2177 char id[9];
2178 id[8] = '\0';
2179
2180 my_RWread(ctx, id, 8, sizeof(id[0]));
2181
2182 if (strcmp(id, MUS_SONG_SIG) == 0)
2183 {
2184 Uint8 version = 0;
2185 my_RWread(ctx, &version, 1, sizeof(version));
2186
2187 debug("Song version = %u", version);
2188
2189 if (version > MUS_VERSION)
2190 {
2191 debug("Unsupported song version");
2192 return 0;
2193 }
2194
2195 if (version >= 6)
2196 my_RWread(ctx, &song->num_channels, 1, sizeof(song->num_channels));
2197 else
2198 {
2199 if (version > 3)
2200 song->num_channels = 4;
2201 else
2202 song->num_channels = 3;
2203 }
2204
2205 my_RWread(ctx, &song->time_signature, 1, sizeof(song->time_signature));
2206
2207 if (version >= 17)
2208 {
2209 my_RWread(ctx, &song->sequence_step, 1, sizeof(song->sequence_step));
2210 }
2211
2212 my_RWread(ctx, &song->num_instruments, 1, sizeof(song->num_instruments));
2213 my_RWread(ctx, &song->num_patterns, 1, sizeof(song->num_patterns));
2214 my_RWread(ctx, song->num_sequences, 1, sizeof(song->num_sequences[0]) * (int)song->num_channels);
2215 my_RWread(ctx, &song->song_length, 1, sizeof(song->song_length));
2216
2217 my_RWread(ctx, &song->loop_point, 1, sizeof(song->loop_point));
2218
2219 if (version >= 12)
2220 my_RWread(ctx, &song->master_volume, 1, 1);
2221
2222 my_RWread(ctx, &song->song_speed, 1, sizeof(song->song_speed));
2223 my_RWread(ctx, &song->song_speed2, 1, sizeof(song->song_speed2));
2224 my_RWread(ctx, &song->song_rate, 1, sizeof(song->song_rate));
2225
2226 if (version > 2) my_RWread(ctx, &song->flags, 1, sizeof(song->flags));
2227 else song->flags = 0;
2228
2229 if (version >= 9) my_RWread(ctx, &song->multiplex_period, 1, sizeof(song->multiplex_period));
2230 else song->multiplex_period = 3;
2231
2232 if (version >= 16)
2233 {
2234 my_RWread(ctx, &song->pitch_inaccuracy, 1, sizeof(song->pitch_inaccuracy));
2235 }
2236 else
2237 {
2238 song->pitch_inaccuracy = 0;
2239 }
2240
2241 /* The file format is little-endian, the following only does something on big-endian machines */
2242
2243 FIX_ENDIAN(song->song_length);
2244 FIX_ENDIAN(song->loop_point);
2245 FIX_ENDIAN(song->time_signature);
2246 FIX_ENDIAN(song->sequence_step);
2247 FIX_ENDIAN(song->num_patterns);
2248 FIX_ENDIAN(song->flags);
2249
2250 for (int i = 0 ; i < (int)song->num_channels ; ++i)
2251 FIX_ENDIAN(song->num_sequences[i]);
2252
2253 Uint8 title_len = 16 + 1; // old length
2254
2255 if (version >= 11)
2256 {
2257 my_RWread(ctx, &title_len, 1, 1);
2258 }
2259
2260 if (version >= 5)
2261 {
2262 memset(song->title, 0, sizeof(song->title));
2263 my_RWread(ctx, song->title, 1, my_min(sizeof(song->title), title_len));
2264 song->title[sizeof(song->title) - 1] = '\0';
2265 }
2266
2267 Uint8 n_fx = 0;
2268
2269 if (version >= 10)
2270 my_RWread(ctx, &n_fx, 1, sizeof(n_fx));
2271 else if (song->flags & MUS_ENABLE_REVERB)
2272 n_fx = 1;
2273
2274 if (n_fx > 0)
2275 {
2276 debug("Song has %u effects", n_fx);
2277 if (version >= 10)
2278 {
2279 memset(&song->fx, 0, sizeof(song->fx[0]) * n_fx);
2280
2281 debug("Loading fx at offset %x (%d/%d)", (Uint32)my_RWtell(ctx), (int)sizeof(song->fx[0]) * n_fx, (int)sizeof(song->fx[0]));
2282
2283 for (int fx = 0 ; fx < n_fx ; ++fx)
2284 inner_load_fx(ctx, &song->fx[fx], version);
2285 }
2286 else
2287 {
2288 for (int fx = 0 ; fx < n_fx ; ++fx)
2289 {
2290 song->fx[fx].flags = CYDFX_ENABLE_REVERB;
2291 if (song->flags & MUS_ENABLE_CRUSH) song->fx[fx].flags |= CYDFX_ENABLE_CRUSH;
2292
2293 for (int i = 0 ; i < 8 ; ++i)
2294 {
2295 Sint32 g, d;
2296 my_RWread(ctx, &g, 1, sizeof(g));
2297 my_RWread(ctx, &d, 1, sizeof(d));
2298
2299 song->fx[fx].rvb.tap[i].gain = g;
2300 song->fx[fx].rvb.tap[i].delay = d;
2301 song->fx[fx].rvb.tap[i].panning = CYD_PAN_CENTER;
2302 song->fx[fx].rvb.tap[i].flags = 1;
2303
2304 FIX_ENDIAN(song->fx[fx].rvb.tap[i].gain);
2305 FIX_ENDIAN(song->fx[fx].rvb.tap[i].delay);
2306 }
2307 }
2308 }
2309 }
2310
2311
2312 for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
2313 {
2314 song->default_volume[i] = MAX_VOLUME;
2315 song->default_panning[i] = 0;
2316 }
2317
2318 if (version >= 13)
2319 {
2320 debug("Loading default volumes at offset %x", (Uint32)my_RWtell(ctx));
2321 my_RWread(ctx, &song->default_volume[0], sizeof(song->default_volume[0]), song->num_channels);
2322 debug("Loading default panning at offset %x", (Uint32)my_RWtell(ctx));
2323 my_RWread(ctx, &song->default_panning[0], sizeof(song->default_panning[0]), song->num_channels);
2324 }
2325
2326 if (song->instrument == NULL)
2327 {
2328 song->instrument = malloc((size_t)song->num_instruments * sizeof(song->instrument[0]));
2329 }
2330
2331 for (int i = 0 ; i < song->num_instruments; ++i)
2332 {
2333 mus_load_instrument_RW(version, ctx, &song->instrument[i], NULL);
2334 }
2335
2336
2337 for (int i = 0 ; i < song->num_channels ; ++i)
2338 {
2339 if (song->num_sequences[i] > 0)
2340 {
2341 if (song->sequence[i] == NULL)
2342 song->sequence[i] = malloc((size_t)song->num_sequences[i] * sizeof(song->sequence[0][0]));
2343
2344 if (version < 8)
2345 {
2346 my_RWread(ctx, song->sequence[i], song->num_sequences[i], sizeof(song->sequence[i][0]));
2347 }
2348 else
2349 {
2350 for (int s = 0 ; s < song->num_sequences[i] ; ++s)
2351 {
2352 my_RWread(ctx, &song->sequence[i][s].position, 1, sizeof(song->sequence[i][s].position));
2353 my_RWread(ctx, &song->sequence[i][s].pattern, 1, sizeof(song->sequence[i][s].pattern));
2354 my_RWread(ctx, &song->sequence[i][s].note_offset, 1, sizeof(song->sequence[i][s].note_offset));
2355 }
2356 }
2357
2358 for (int s = 0 ; s < song->num_sequences[i] ; ++s)
2359 {
2360 FIX_ENDIAN(song->sequence[i][s].position);
2361 FIX_ENDIAN(song->sequence[i][s].pattern);
2362 }
2363 }
2364 }
2365
2366 if (song->pattern == NULL)
2367 {
2368 song->pattern = calloc((size_t)song->num_patterns, sizeof(song->pattern[0]));
2369 //memset(song->pattern, 0, (size_t)song->num_patterns * sizeof(song->pattern[0]));
2370 }
2371
2372 for (int i = 0 ; i < song->num_patterns; ++i)
2373 {
2374 Uint16 steps;
2375 my_RWread(ctx, &steps, 1, sizeof(song->pattern[i].num_steps));
2376
2377 FIX_ENDIAN(steps);
2378
2379 if (song->pattern[i].step == NULL)
2380 song->pattern[i].step = calloc((size_t)steps, sizeof(song->pattern[i].step[0]));
2381 else if (steps > song->pattern[i].num_steps)
2382 song->pattern[i].step = realloc(song->pattern[i].step, (size_t)steps * sizeof(song->pattern[i].step[0]));
2383
2384 song->pattern[i].num_steps = steps;
2385
2386 if (version >= 24)
2387 my_RWread(ctx, &song->pattern[i].color, 1, sizeof(song->pattern[i].color));
2388 else
2389 song->pattern[i].color = 0;
2390
2391 if (version < 8)
2392 {
2393 size_t s = sizeof(song->pattern[i].step[0]);
2394 if (version < 2)
2395 s = sizeof(Uint8)*3;
2396 else
2397 s = sizeof(Uint8)*3 + sizeof(Uint16) + 1; // aligment issue in version 6 songs
2398
2399 for (int step = 0 ; step < song->pattern[i].num_steps ; ++step)
2400 {
2401 my_RWread(ctx, &song->pattern[i].step[step], 1, s);
2402 FIX_ENDIAN(song->pattern[i].step[step].command);
2403 }
2404 }
2405 else
2406 {
2407 int len = song->pattern[i].num_steps / 2 + (song->pattern[i].num_steps & 1);
2408
2409 Uint8 *packed = malloc(sizeof(Uint8) * len);
2410 Uint8 *current = packed;
2411
2412 my_RWread(ctx, packed, sizeof(Uint8), len);
2413
2414 for (int s = 0 ; s < song->pattern[i].num_steps ; ++s)
2415 {
2416 Uint8 bits = (s & 1 || s == song->pattern[i].num_steps - 1) ? (*current & 0xf) : (*current >> 4);
2417
2418 if (bits & MUS_PAK_BIT_NOTE)
2419 my_RWread(ctx, &song->pattern[i].step[s].note, 1, sizeof(song->pattern[i].step[s].note));
2420 else
2421 song->pattern[i].step[s].note = MUS_NOTE_NONE;
2422
2423 if (bits & MUS_PAK_BIT_INST)
2424 my_RWread(ctx, &song->pattern[i].step[s].instrument, 1, sizeof(song->pattern[i].step[s].instrument));
2425 else
2426 song->pattern[i].step[s].instrument = MUS_NOTE_NO_INSTRUMENT;
2427
2428 if (bits & MUS_PAK_BIT_CTRL)
2429 {
2430 my_RWread(ctx, &song->pattern[i].step[s].ctrl, 1, sizeof(song->pattern[i].step[s].ctrl));
2431
2432 if (version >= 14)
2433 bits |= song->pattern[i].step[s].ctrl & ~7;
2434
2435 song->pattern[i].step[s].ctrl &= 7;
2436 }
2437 else
2438 song->pattern[i].step[s].ctrl = 0;
2439
2440 if (bits & MUS_PAK_BIT_CMD)
2441 my_RWread(ctx, &song->pattern[i].step[s].command, 1, sizeof(song->pattern[i].step[s].command));
2442 else
2443 song->pattern[i].step[s].command = 0;
2444
2445 FIX_ENDIAN(song->pattern[i].step[s].command);
2446
2447 if (bits & MUS_PAK_BIT_VOLUME)
2448 {
2449 my_RWread(ctx, &song->pattern[i].step[s].volume, 1, sizeof(song->pattern[i].step[s].volume));
2450 }
2451 else
2452 {
2453 song->pattern[i].step[s].volume = MUS_NOTE_NO_VOLUME;
2454 }
2455
2456 if (s & 1) ++current;
2457 }
2458
2459 free(packed);
2460 }
2461 }
2462
2463 for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i)
2464 {
2465 cyd_wave_entry_init(&wavetable_entries[i], NULL, 0, 0, 0, 0, 0);
2466 }
2467
2468 if (version >= 12)
2469 {
2470 Uint8 max_wt = 0;
2471 my_RWread(ctx, &max_wt, 1, sizeof(Uint8));
2472
2473 for (int i = 0 ; i < max_wt ; ++i)
2474 {
2475 load_wavetable_entry(version, &wavetable_entries[i], ctx);
2476 }
2477
2478 song->wavetable_names = malloc(max_wt * sizeof(char*));
2479
2480 if (version >= 26)
2481 {
2482 for (int i = 0 ; i < max_wt ; ++i)
2483 {
2484 Uint8 len = 0;
2485 song->wavetable_names[i] = malloc(MUS_WAVETABLE_NAME_LEN + 1);
2486 memset(song->wavetable_names[i], 0, MUS_WAVETABLE_NAME_LEN + 1);
2487
2488 my_RWread(ctx, &len, 1, 1);
2489 my_RWread(ctx, song->wavetable_names[i], len, sizeof(char));
2490 }
2491 }
2492 else
2493 {
2494 for (int i = 0 ; i < max_wt ; ++i)
2495 {
2496 song->wavetable_names[i] = malloc(MUS_WAVETABLE_NAME_LEN + 1);
2497 memset(song->wavetable_names[i], 0, MUS_WAVETABLE_NAME_LEN + 1);
2498 }
2499 }
2500
2501 song->num_wavetables = max_wt;
2502 }
2503 else
2504 song->num_wavetables = 0;
2505
2506 return 1;
2507 }
2508
2509 return 0;
2510 }
2511
2512
mus_load_song(const char * path,MusSong * song,CydWavetableEntry * wavetable_entries)2513 int mus_load_song(const char *path, MusSong *song, CydWavetableEntry *wavetable_entries)
2514 {
2515 RWops *ctx = RWFromFile(path, "rb");
2516
2517 if (ctx)
2518 {
2519 int r = mus_load_song_RW(ctx, song, wavetable_entries);
2520 my_RWclose(ctx);
2521
2522 return r;
2523 }
2524
2525 return 0;
2526 }
2527
2528
mus_free_song(MusSong * song)2529 void mus_free_song(MusSong *song)
2530 {
2531 free(song->instrument);
2532
2533 for (int i = 0 ; i < MUS_MAX_CHANNELS; ++i)
2534 {
2535 free(song->sequence[i]);
2536 }
2537
2538 for (int i = 0 ; i < song->num_patterns; ++i)
2539 {
2540 free(song->pattern[i].step);
2541 }
2542
2543 for (int i = 0 ; i < song->num_wavetables; ++i)
2544 {
2545 free(song->wavetable_names[i]);
2546 }
2547
2548 free(song->wavetable_names);
2549
2550 free(song->pattern);
2551 }
2552
2553
mus_release(MusEngine * mus,int chan)2554 void mus_release(MusEngine *mus, int chan)
2555 {
2556 cyd_lock(mus->cyd, 1);
2557 cyd_enable_gate(mus->cyd, &mus->cyd->channel[chan], 0);
2558
2559 cyd_lock(mus->cyd, 0);
2560 }
2561
2562
mus_load_instrument_file(Uint8 version,FILE * f,MusInstrument * inst,CydWavetableEntry * wavetable_entries)2563 int mus_load_instrument_file(Uint8 version, FILE *f, MusInstrument *inst, CydWavetableEntry *wavetable_entries)
2564 {
2565 RWops *rw = RWFromFP(f, 0);
2566
2567 if (rw)
2568 {
2569 int r = mus_load_instrument_RW(version, rw, inst, wavetable_entries);
2570
2571 my_RWclose(rw);
2572
2573 return r;
2574 }
2575
2576 return 0;
2577 }
2578
2579
mus_load_instrument_file2(FILE * f,MusInstrument * inst,CydWavetableEntry * wavetable_entries)2580 int mus_load_instrument_file2(FILE *f, MusInstrument *inst, CydWavetableEntry *wavetable_entries)
2581 {
2582 RWops *rw = RWFromFP(f, 0);
2583
2584 if (rw)
2585 {
2586 int r = mus_load_instrument_RW2(rw, inst, wavetable_entries);
2587
2588 my_RWclose(rw);
2589
2590 return r;
2591 }
2592
2593 return 0;
2594 }
2595
2596
mus_load_song_file(FILE * f,MusSong * song,CydWavetableEntry * wavetable_entries)2597 int mus_load_song_file(FILE *f, MusSong *song, CydWavetableEntry *wavetable_entries)
2598 {
2599 RWops *rw = RWFromFP(f, 0);
2600
2601 if (rw)
2602 {
2603 int r = mus_load_song_RW(rw, song, wavetable_entries);
2604
2605 my_RWclose(rw);
2606
2607 return r;
2608 }
2609
2610 return 0;
2611 }
2612
2613
mus_get_playtime_at(MusSong * song,int position)2614 Uint32 mus_get_playtime_at(MusSong *song, int position)
2615 {
2616 Uint32 ticks = 0;
2617 int pos = 0;
2618 int seq_pos[MUS_MAX_CHANNELS] = {0}, pattern_pos[MUS_MAX_CHANNELS] = {0};
2619 MusPattern *pattern[MUS_MAX_CHANNELS] = {0};
2620 int spd1 = song->song_speed, spd2 = song->song_speed2, rate = song->song_rate;
2621
2622 while (pos < position)
2623 {
2624 for (int t = 0 ; t < song->num_channels ; ++t)
2625 {
2626 if (seq_pos[t] < song->num_sequences[t])
2627 {
2628 if (song->sequence[t][seq_pos[t]].position == pos)
2629 {
2630 if (seq_pos[t] < song->num_sequences[t])
2631 {
2632 pattern_pos[t] = 0;
2633
2634 pattern[t] = &song->pattern[song->sequence[t][seq_pos[t]].pattern];
2635
2636 seq_pos[t]++;
2637 }
2638 }
2639
2640 if (pattern[t] && pattern_pos[t] < pattern[t]->num_steps)
2641 {
2642 Uint16 command = pattern[t]->step[pattern_pos[t]].command;
2643
2644 if ((command & 0xff00) == MUS_FX_SET_SPEED)
2645 {
2646 spd1 = command & 0xf;
2647 spd2 = (command & 0xf0) >> 4;
2648
2649 if (!spd2)
2650 spd2 = spd1;
2651 }
2652 else if ((command & 0xff00) == MUS_FX_SET_RATE)
2653 {
2654 rate = command & 0xff;
2655
2656 if (rate < 1)
2657 rate = 1;
2658 }
2659 else if ((command & 0xff00) == MUS_FX_SKIP_PATTERN)
2660 {
2661 pos += pattern[t]->num_steps - 1 - pattern_pos[t];
2662 }
2663 }
2664
2665 }
2666
2667 pattern_pos[t]++;
2668 }
2669
2670 int spd = pos & 1 ? spd2 : spd1;
2671
2672 ticks += (1000 * spd) / rate;
2673
2674 ++pos;
2675 }
2676
2677 return ticks;
2678 }
2679
2680
mus_set_channel_volume(MusEngine * mus,int chan,int volume)2681 void mus_set_channel_volume(MusEngine* mus, int chan, int volume)
2682 {
2683 MusChannel *chn = &mus->channel[chan];
2684 CydChannel *cydchn = &mus->cyd->channel[chan];
2685 MusTrackStatus *track_status = &mus->song_track[chan];
2686
2687 chn->volume = my_min(volume, MAX_VOLUME);
2688 update_volumes(mus, track_status, chn, cydchn, track_status->volume);
2689 }
2690