struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / support / regression / tests / cvu_play_music.c
blob3b7a371baa1c4ddd4b4963d313849caad348b7fe
1 /* cvu_play_music.c
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.
5 */
7 #include <testfwk.h>
9 #ifdef __SDCC
10 #pragma std_c99
11 #endif
13 #pragma disable_warning 85
15 #include <stdint.h>
16 #include <stdbool.h>
18 enum cv_soundchannel {
19 CV_SOUNDCHANNEL_0 = 0x0,
20 CV_SOUNDCHANNEL_1 = 0x2,
21 CV_SOUNDCHANNEL_2 = 0x4,
22 CV_SOUNDCHANNEL_NOISE = 0x6
25 struct cvu_music
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)
39 return(60);
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;
77 else
79 bool pause = false;
80 const uint16_t note = *(music->notes);
82 cv_set_attenuation(music->channel, 0);
84 if(note == 0xffff)
85 return(false);
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;
93 if(!length)
94 length = 0x10;
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;
100 switch(rel_length)
102 case 0: // Legato
103 break;
104 case 1: // Staccato
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;
108 break;
109 case 2:
110 music->pause_ticks_remaining = music->note_ticks_remaining >> 1;
111 music->note_ticks_remaining -= music->pause_ticks_remaining;
112 break;
113 default: // Standard
114 music->pause_ticks_remaining = music->note_ticks_remaining >> 2;
115 music->note_ticks_remaining -= music->pause_ticks_remaining;
116 break;
120 // Frequency calculations:
122 uint8_t octave, halftone;
123 uint16_t frequency_divider;
125 halftone = (note >> 8) & 0xf;
126 pause = (halftone == 0xf);
127 if(!pause)
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]));
140 music->notes++;
142 return(true);
144 #endif
146 void testBug(void)
148 struct cvu_music music;
149 cvu_init_music(&music);
150 #if !defined(__SDCC_pdk14) // Lack of memory
151 cvu_play_music(&music);
152 #endif