1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
/* cvu_play_music.c
From the function of the same name in the libcvu library for the ColecoVision
This file has been included in the tests, since it uses some z80 peephole rules
not used elsewhere in the regression tests.
*/
#include <testfwk.h>
#ifdef __SDCC
#pragma std_c99
#endif
#pragma disable_warning 85
#include <stdint.h>
#include <stdbool.h>
enum cv_soundchannel {
CV_SOUNDCHANNEL_0 = 0x0,
CV_SOUNDCHANNEL_1 = 0x2,
CV_SOUNDCHANNEL_2 = 0x4,
CV_SOUNDCHANNEL_NOISE = 0x6
};
struct cvu_music
{
enum cv_soundchannel channel;
const uint8_t *volume;
const uint16_t *tuning;
uint8_t sixteenth_notes_per_second;
const uint16_t *notes;
uint16_t note_ticks_remaining;
uint16_t pause_ticks_remaining;
};
unsigned char cv_get_vint_frequency(void)
{
return(60);
}
void cv_set_attenuation(enum cv_soundchannel channel, uint8_t dezibel)
{
}
void cv_set_frequency(enum cv_soundchannel channel, uint16_t frequency_divider)
{
}
const uint16_t CVU_TUNING_ISO16_EQUAL[15] = {54719, 51648, 48749, 46013, 43431, 40993, 38692, 36521, 34471, 32536, 30710, 28987, 0, 0, 0};
const uint8_t CVU_VOLUME_DEFAULT[4] = {20, 16, 12, 8};
const uint16_t CVU_EMPTY_MUSIC = 0xffff;
void cvu_init_music(struct cvu_music *music)
{
music->channel = CV_SOUNDCHANNEL_0;
music->volume = CVU_VOLUME_DEFAULT;
music->tuning = CVU_TUNING_ISO16_EQUAL;
music->sixteenth_notes_per_second = 10;
music->note_ticks_remaining = 0;
music->pause_ticks_remaining = 0;
music->notes = &CVU_EMPTY_MUSIC;
}
#if !defined(__SDCC_pdk14) // Lack of memory
bool cvu_play_music(struct cvu_music *restrict music)
{
if(music->note_ticks_remaining >= music->sixteenth_notes_per_second)
music->note_ticks_remaining -= music->sixteenth_notes_per_second;
else if(music->pause_ticks_remaining >= music->sixteenth_notes_per_second)
{
cv_set_attenuation(music->channel, 0);
music->pause_ticks_remaining -= music->sixteenth_notes_per_second;
}
else
{
bool pause = false;
const uint16_t note = *(music->notes);
cv_set_attenuation(music->channel, 0);
if(note == 0xffff)
return(false);
// Length calculations:
{
uint8_t length, rel_length;
uint16_t leftover_ticks = music->note_ticks_remaining + music->pause_ticks_remaining; // Avoid desynchronization of multi-voice music.
length = (note >> 4) & 0xf;
if(!length)
length = 0x10;
music->note_ticks_remaining = length * cv_get_vint_frequency();
music->note_ticks_remaining += leftover_ticks;
music->note_ticks_remaining -= music->sixteenth_notes_per_second;
rel_length = (note >> 2) & 0x3;
switch(rel_length)
{
case 0: // Legato
break;
case 1: // Staccato
music->pause_ticks_remaining = music->note_ticks_remaining;
music->note_ticks_remaining = music->note_ticks_remaining >> 2;
music->pause_ticks_remaining -= music->note_ticks_remaining;
break;
case 2:
music->pause_ticks_remaining = music->note_ticks_remaining >> 1;
music->note_ticks_remaining -= music->pause_ticks_remaining;
break;
default: // Standard
music->pause_ticks_remaining = music->note_ticks_remaining >> 2;
music->note_ticks_remaining -= music->pause_ticks_remaining;
break;
}
}
// Frequency calculations:
{
uint8_t octave, halftone;
uint16_t frequency_divider;
halftone = (note >> 8) & 0xf;
pause = (halftone == 0xf);
if(!pause)
{
frequency_divider = music->tuning[halftone];
octave = (note >> 12);
cv_set_frequency(music->channel, (frequency_divider >> octave) <= 32736 ? frequency_divider >> octave : frequency_divider >> (octave + 1));
}
}
// Loudness calculations:
{
cv_set_attenuation(music->channel, pause ? 0 : (music->volume[note & 0x3]));
}
music->notes++;
}
return(true);
}
#endif
void testBug(void)
{
struct cvu_music music;
cvu_init_music(&music);
#if !defined(__SDCC_pdk14) // Lack of memory
cvu_play_music(&music);
#endif
}
|