2 From the function of the same name in the libcvu library for the ColecoVision
3 This file has been included in the tests, since it uses some z80 peephole rules
4 not used elsewhere in the regression tests.
13 #pragma disable_warning 85
18 enum cv_soundchannel
{
19 CV_SOUNDCHANNEL_0
= 0x0,
20 CV_SOUNDCHANNEL_1
= 0x2,
21 CV_SOUNDCHANNEL_2
= 0x4,
22 CV_SOUNDCHANNEL_NOISE
= 0x6
27 enum cv_soundchannel channel
;
28 const uint8_t *volume
;
29 const uint16_t *tuning
;
30 uint8_t sixteenth_notes_per_second
;
31 const uint16_t *notes
;
33 uint16_t note_ticks_remaining
;
34 uint16_t pause_ticks_remaining
;
37 unsigned char cv_get_vint_frequency(void)
42 void cv_set_attenuation(enum cv_soundchannel channel
, uint8_t dezibel
)
46 void cv_set_frequency(enum cv_soundchannel channel
, uint16_t frequency_divider
)
50 const uint16_t CVU_TUNING_ISO16_EQUAL
[15] = {54719, 51648, 48749, 46013, 43431, 40993, 38692, 36521, 34471, 32536, 30710, 28987, 0, 0, 0};
52 const uint8_t CVU_VOLUME_DEFAULT
[4] = {20, 16, 12, 8};
54 const uint16_t CVU_EMPTY_MUSIC
= 0xffff;
56 void cvu_init_music(struct cvu_music
*music
)
58 music
->channel
= CV_SOUNDCHANNEL_0
;
59 music
->volume
= CVU_VOLUME_DEFAULT
;
60 music
->tuning
= CVU_TUNING_ISO16_EQUAL
;
61 music
->sixteenth_notes_per_second
= 10;
62 music
->note_ticks_remaining
= 0;
63 music
->pause_ticks_remaining
= 0;
64 music
->notes
= &CVU_EMPTY_MUSIC
;
67 #if !defined(__SDCC_pdk14) // Lack of memory
68 bool cvu_play_music(struct cvu_music
*restrict music
)
70 if(music
->note_ticks_remaining
>= music
->sixteenth_notes_per_second
)
71 music
->note_ticks_remaining
-= music
->sixteenth_notes_per_second
;
72 else if(music
->pause_ticks_remaining
>= music
->sixteenth_notes_per_second
)
74 cv_set_attenuation(music
->channel
, 0);
75 music
->pause_ticks_remaining
-= music
->sixteenth_notes_per_second
;
80 const uint16_t note
= *(music
->notes
);
82 cv_set_attenuation(music
->channel
, 0);
87 // Length calculations:
89 uint8_t length
, rel_length
;
90 uint16_t leftover_ticks
= music
->note_ticks_remaining
+ music
->pause_ticks_remaining
; // Avoid desynchronization of multi-voice music.
92 length
= (note
>> 4) & 0xf;
95 music
->note_ticks_remaining
= length
* cv_get_vint_frequency();
96 music
->note_ticks_remaining
+= leftover_ticks
;
97 music
->note_ticks_remaining
-= music
->sixteenth_notes_per_second
;
99 rel_length
= (note
>> 2) & 0x3;
105 music
->pause_ticks_remaining
= music
->note_ticks_remaining
;
106 music
->note_ticks_remaining
= music
->note_ticks_remaining
>> 2;
107 music
->pause_ticks_remaining
-= music
->note_ticks_remaining
;
110 music
->pause_ticks_remaining
= music
->note_ticks_remaining
>> 1;
111 music
->note_ticks_remaining
-= music
->pause_ticks_remaining
;
114 music
->pause_ticks_remaining
= music
->note_ticks_remaining
>> 2;
115 music
->note_ticks_remaining
-= music
->pause_ticks_remaining
;
120 // Frequency calculations:
122 uint8_t octave
, halftone
;
123 uint16_t frequency_divider
;
125 halftone
= (note
>> 8) & 0xf;
126 pause
= (halftone
== 0xf);
129 frequency_divider
= music
->tuning
[halftone
];
131 octave
= (note
>> 12);
132 cv_set_frequency(music
->channel
, (frequency_divider
>> octave
) <= 32736 ? frequency_divider
>> octave
: frequency_divider
>> (octave
+ 1));
136 // Loudness calculations:
138 cv_set_attenuation(music
->channel
, pause
? 0 : (music
->volume
[note
& 0x3]));
148 struct cvu_music music
;
149 cvu_init_music(&music
);
150 #if !defined(__SDCC_pdk14) // Lack of memory
151 cvu_play_music(&music
);