aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-05-28 19:22:49 +0200
committerBad Diode <bd@badd10de.dev>2021-05-28 19:22:49 +0200
commit65ce84c8a57956ac685256b50d496cf305eac66e (patch)
tree357de9155a66452f8b458113ed061fe41db77056 /src
parent4ea00e4dcbb390f9fec53034ac1a62cc6fb308d0 (diff)
downloaduxngba-65ce84c8a57956ac685256b50d496cf305eac66e.tar.gz
uxngba-65ce84c8a57956ac685256b50d496cf305eac66e.zip
Cleaup some leftover code and comments
Diffstat (limited to 'src')
-rw-r--r--src/apu.c (renamed from src/uxn/devices/apu.c)190
-rw-r--r--src/common.h5
-rw-r--r--src/filesystem.c2
-rw-r--r--src/main.c46
4 files changed, 106 insertions, 137 deletions
diff --git a/src/uxn/devices/apu.c b/src/apu.c
index 47151a6..8dd4ce5 100644
--- a/src/uxn/devices/apu.c
+++ b/src/apu.c
@@ -1,24 +1,3 @@
1// Calculated as ((261.6 / 18157) << 17) for C4. If multiplied by sampling rate
2// we will have a u32 (15.17) fixed-point number. This should be enough to
3// accurately portray samples up to 75300 Hz.
4static u16 pitch_table[120] = {
5 59, 62, 66, 70, 74, 78, 83, 88,
6 93, 99, 105, 111, 118, 125, 132, 140,
7 148, 157, 166, 176, 187, 198, 210, 222,
8 236, 250, 264, 280, 297, 315, 333, 353,
9 374, 396, 420, 445, 472, 500, 529, 561,
10 594, 630, 667, 707, 749, 793, 841, 891,
11 944, 1000, 1059, 1122, 1189, 1260, 1335, 1414,
12 1498, 1587, 1682, 1782, 1888, 2000, 2119, 2245,
13 2379, 2520, 2670, 2829, 2997, 3175, 3364, 3564,
14 3776, 4001, 4239, 4491, 4758, 5041, 5341, 5658,
15 5995, 6351, 6729, 7129, 7553, 8002, 8478, 8982,
16 9517, 10083, 10682, 11317, 11990, 12703, 13459, 14259,
17 15107, 16005, 16957, 17965, 19034, 20166, 21365, 22635,
18 23981, 25407, 26918, 28519, 30215, 32011, 33915, 35931,
19 38068, 40332, 42730, 45271, 47963, 50815, 53837, 57038,
20};
21
22// 1//
23// REG_TM0D frequency buffer size 2// REG_TM0D frequency buffer size
24// | | | 3// | | |
@@ -48,7 +27,7 @@ typedef struct Audio {
48 27
49typedef struct AudioChannel { 28typedef struct AudioChannel {
50 // Pointer to the raw data in the ROM. 29 // Pointer to the raw data in the ROM.
51 s8 *data; 30 u8 *data;
52 // Current position in the data (20.12 fixed-point). 31 // Current position in the data (20.12 fixed-point).
53 u32 pos; 32 u32 pos;
54 // Increment (20.12 fixed-point). 33 // Increment (20.12 fixed-point).
@@ -63,70 +42,75 @@ typedef struct AudioChannel {
63 u8 pitch; 42 u8 pitch;
64 // Keeping track of the original adsr values. 43 // Keeping track of the original adsr values.
65 u16 adsr; 44 u16 adsr;
66 // The filter is built with the ADSR and has a duration of 60 ticks. Since 45 // The filter is built with the ADSR and has a maximum duration of
67 // weare synced at 60FPS it should be pretty straightforward. 46 // 4 seconds. Each component can last up to 1 second.
68 u8 filter[241]; 47 u8 filter[240];
69 // Current position in the filter (0-60). 48 // Current position in the filter (0-60).
70 u8 filter_pos; 49 u8 filter_pos;
71 // Duration of the filter. 50 // Duration of the filter.
72 u8 filter_len; 51 u8 filter_len;
73} AudioChannel; 52} AudioChannel;
74 53
75// NOTE: fixed-point (1.6) precision for volume adjustments. 54// Calculated as ((261.6 / 18157) << 17) for C4. If multiplied by sampling rate
76typedef u32 fp32; 55// we will have a u32 (15.17) fixed-point number. This should be enough to
77 56// accurately portray samples up to 75300 Hz.
78inline 57static u16 pitch_table[120] = {
79fp32 58 59, 62, 66, 70, 74, 78, 83, 88,
80fp_mul(fp32 a, fp32 b) { 59 93, 99, 105, 111, 118, 125, 132, 140,
81 return (a * b) >> 6; 60 148, 157, 166, 176, 187, 198, 210, 222,
82} 61 236, 250, 264, 280, 297, 315, 333, 353,
83 62 374, 396, 420, 445, 472, 500, 529, 561,
84inline 63 594, 630, 667, 707, 749, 793, 841, 891,
85fp32 64 944, 1000, 1059, 1122, 1189, 1260, 1335, 1414,
86fp_div(fp32 a, fp32 b) { 65 1498, 1587, 1682, 1782, 1888, 2000, 2119, 2245,
87 return (a << 6) / b; 66 2379, 2520, 2670, 2829, 2997, 3175, 3364, 3564,
88} 67 3776, 4001, 4239, 4491, 4758, 5041, 5341, 5658,
89 68 5995, 6351, 6729, 7129, 7553, 8002, 8478, 8982,
90inline 69 9517, 10083, 10682, 11317, 11990, 12703, 13459, 14259,
91fp32 70 15107, 16005, 16957, 17965, 19034, 20166, 21365, 22635,
92fp_lerp(fp32 y0, fp32 y1, fp32 x) { 71 23981, 25407, 26918, 28519, 30215, 32011, 33915, 35931,
93 return y0 + fp_mul(x, (y1 - y0)); 72 38068, 40332, 42730, 45271, 47963, 50815, 53837, 57038,
94} 73};
95
96 74
97IWRAM_CODE 75IWRAM_CODE
98void 76void
99build_adsr(AudioChannel *chan, u16 adsr) { 77build_adsr(AudioChannel *chan, u16 adsr) {
100 // u8 a = (adsr >> 12); 78 chan->filter_pos = 0;
79 if (adsr == chan->adsr) {
80 return;
81 }
82
101 u8 a = (adsr >> 12); 83 u8 a = (adsr >> 12);
102 u8 d = (adsr >> 8) & 0xF; 84 u8 d = (adsr >> 8) & 0xF;
103 u8 s = (adsr >> 4) & 0xF; 85 u8 s = (adsr >> 4) & 0xF;
104 u8 r = (adsr >> 0) & 0xF; 86 u8 r = (adsr >> 0) & 0xF;
105 87
106 // Initialize the filter array. 88 // Initialize the filter array.
107 memset(chan->filter, 0, sizeof(chan->filter)); 89 dma_fill(chan->filter, 0, sizeof(chan->filter), 3);
108 u8 k = 0; 90 u8 k = 0;
109 91
110 // Attack. 92 // Attack.
93 u32 interval = FP_DIV(1 << 6, (4 * a) << 6, 6);
111 for (u32 i = 0; i < 4 * a; ++i) { 94 for (u32 i = 0; i < 4 * a; ++i) {
112 chan->filter[k++] = fp_lerp(0, chan->vol, fp_div(i << 6, (4 * a) << 6)); 95 chan->filter[k++] = FP_LERP(0, chan->vol, i * interval, 6);
113 } 96 }
114 // Decay. 97 // Decay.
98 interval = FP_DIV(1 << 6, (4 * d) << 6, 6);
115 for (u32 i = 0; i < 4 * d; ++i) { 99 for (u32 i = 0; i < 4 * d; ++i) {
116 chan->filter[k++] = fp_lerp(chan->vol, chan->vol / 2, fp_div(i << 6, (4 * d) << 6)); 100 chan->filter[k++] = FP_LERP(chan->vol, chan->vol / 2, i * interval, 6);
117 } 101 }
118 // Sustain. 102 // Sustain.
119 for (u32 i = 0; i < 4 * s; ++i) { 103 for (u32 i = 0; i < 4 * s; ++i) {
120 chan->filter[k++] = chan->vol / 2; 104 chan->filter[k++] = chan->vol / 2;
121 } 105 }
122 // Release. 106 // Release.
107 interval = FP_DIV(1 << 6, (4 * r) << 6, 6);
123 for (u32 i = 0; i < 4 * r; ++i) { 108 for (u32 i = 0; i < 4 * r; ++i) {
124 chan->filter[k++] = fp_lerp(chan->vol / 2, 0, fp_div(i << 6, (4 * r) << 6)); 109 chan->filter[k++] = FP_LERP(chan->vol / 2, 0, i * interval, 6);
125 } 110 }
126 111
127 // Setup the channel vars. 112 // Setup the channel vars.
128 chan->adsr = adsr; 113 chan->adsr = adsr;
129 chan->filter_pos = 0;
130 chan->filter_len = k; 114 chan->filter_len = k;
131} 115}
132 116
@@ -153,35 +137,57 @@ init_sound(void) {
153 | SOUND_DSOUND_RIGHT_A 137 | SOUND_DSOUND_RIGHT_A
154 | SOUND_DSOUND_RESET_A; 138 | SOUND_DSOUND_RESET_A;
155 139
140 // The timer depends on the buffer length.
156 TIMER_DATA_0 = AUDIO_TIMER; 141 TIMER_DATA_0 = AUDIO_TIMER;
157 TIMER_CTRL_0 = TIMER_CTRL_ENABLE; 142 TIMER_CTRL_0 = TIMER_CTRL_ENABLE;
158} 143}
159 144
160void sound_vsync() { 145void
161 // buffer 1 just got over 146sound_vsync() {
162 if(audio.active_buffer == 1) { 147 if(audio.active_buffer == 1) {
163 // Start playing buffer 0 148 // Start playing and set the backbuffer.
164 dma_transfer_copy(SOUND_FIFO_A, audio.mix_buffer, 1, 1, 149 dma_transfer_copy(SOUND_FIFO_A, audio.mix_buffer, 1, 1, DMA_DST_FIXED
165 DMA_DST_FIXED | DMA_CHUNK_32 | DMA_REFRESH | DMA_REPEAT | DMA_ENABLE); 150 | DMA_CHUNK_32 | DMA_REFRESH | DMA_REPEAT | DMA_ENABLE);
166
167 // Set the current buffer pointer to the start of buffer 1
168 audio.current_buffer = audio.mix_buffer + AUDIO_BUF_LEN; 151 audio.current_buffer = audio.mix_buffer + AUDIO_BUF_LEN;
169 audio.active_buffer = 0; 152 audio.active_buffer = 0;
170 } else { 153 } else {
171 // buffer 0 just got over 154 // Flip front/backbuffer.
172 // DMA points to buffer 1 already, so don't bother stopping and resetting it
173 // Set the current buffer pointer to the start of buffer 0
174 audio.current_buffer = audio.mix_buffer; 155 audio.current_buffer = audio.mix_buffer;
175 audio.active_buffer = 1; 156 audio.active_buffer = 1;
176 } 157 }
177} 158}
178 159
179IWRAM_CODE 160IWRAM_CODE
180void sound_mix() { 161void
181 // Initialize and clear mix_buffer. 162update_channel(AudioChannel *c, u8 *data, u16 length, u8 pitch, u16 adsr,
182 s16 mix_buffer[AUDIO_BUF_LEN]; 163 u8 vol, bool loop) {
183 u32 fill = 0; 164 c->pos = 0;
184 dma_fill(mix_buffer, fill, sizeof(mix_buffer), 3); 165 c->length = length << 12;
166 c->data = data;
167 c->vol = vol;
168 c->pitch = pitch;
169
170 if (loop) {
171 c->loop_length = c->length;
172 } else {
173 c->loop_length = 0;
174 }
175
176 u32 sampling_rate = length;
177 if (length > 256) {
178 sampling_rate = 44100;
179 }
180 c->inc = (pitch_table[c->pitch] * sampling_rate) >> 5;
181
182 build_adsr(c, adsr);
183}
184
185IWRAM_CODE
186void
187sound_mix(void) {
188 // Clear mix_buffer.
189 u16 mix_buffer[AUDIO_BUF_LEN];
190 dma_fill(mix_buffer, 0, sizeof(mix_buffer), 3);
185 191
186 // Mix channels into the temporary buffer. 192 // Mix channels into the temporary buffer.
187 for (size_t j = 0; j < POLYPHONY; ++j) { 193 for (size_t j = 0; j < POLYPHONY; ++j) {
@@ -198,33 +204,23 @@ void sound_mix() {
198 continue; 204 continue;
199 } 205 }
200 } 206 }
201 if (ch->pos + ch->inc * AUDIO_BUF_LEN >= ch->length) { 207
202 // Sample is going to finish, need to consider this for looping or 208 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) {
203 // stopping. 209 // Remember we are using fixed point values.
204 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) { 210 mix_buffer[i] += (0x80 ^ (s8)ch->data[ch->pos >> 12]) * vol;
205 // Remember we are using fixed point values. 211 ch->pos += ch->inc;
206 mix_buffer[i] += (0x80 ^ ch->data[ch->pos >> 12]) * vol; 212
207 ch->pos += ch->inc; 213 if (ch->pos >= ch->length) {
208 214 // If looping is not active disable the channel.
209 if (ch->pos >= ch->length) { 215 if (ch->loop_length == 0) {
210 // If looping is not active disable the channel. 216 ch->data = NULL;
211 if (ch->loop_length == 0) { 217 break;
212 ch->data = NULL; 218 }
213 break; 219
214 } 220 // Loop the sample.
215 221 while (ch->pos >= ch->length) {
216 // Loop the sample. 222 ch->pos -= ch->loop_length;
217 while (ch->pos >= ch->length) {
218 ch->pos -= ch->loop_length;
219 }
220 } 223 }
221 }
222 } else {
223 // Sample still have room to go, no need to check for looping or
224 // end of sample.
225 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) {
226 mix_buffer[i] += (0x80 ^ ch->data[ch->pos>>12]) * vol;
227 ch->pos += ch->inc;
228 } 224 }
229 } 225 }
230 } 226 }
@@ -234,9 +230,9 @@ void sound_mix() {
234 u32 *buf_ptr = audio.current_buffer; 230 u32 *buf_ptr = audio.current_buffer;
235 for (size_t i = 0; i < AUDIO_BUF_LEN / 4; i++) { 231 for (size_t i = 0; i < AUDIO_BUF_LEN / 4; i++) {
236 u64 mix = mix_ptr[i]; 232 u64 mix = mix_ptr[i];
237 buf_ptr[i] = (mix >> 8) & 0xFF 233 buf_ptr[i] = ((mix >> 8) & 0xFF)
238 | (mix >> 16) & 0xFF00 234 | ((mix >> 16) & 0xFF00)
239 | (mix >> 24) & 0xFF0000 235 | ((mix >> 24) & 0xFF0000)
240 | (mix >> 32) & 0xFF000000; 236 | ((mix >> 32) & 0xFF000000);
241 } 237 }
242} 238}
diff --git a/src/common.h b/src/common.h
index 048708b..0fe2752 100644
--- a/src/common.h
+++ b/src/common.h
@@ -722,6 +722,11 @@ wait_vsync(void) {
722#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) 722#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X))
723#define LEN(ARR) (sizeof(ARR) / sizeof((ARR)[0])) 723#define LEN(ARR) (sizeof(ARR) / sizeof((ARR)[0]))
724 724
725// Fixed-point arithmetic for (i.P) numbers.
726#define FP_MUL(A,B,P) (((A) * (B)) >> (P))
727#define FP_DIV(A,B,P) (((A) << (P)) / (B))
728#define FP_LERP(Y0,Y1,X,P) ((Y0) + FP_MUL((X), ((Y1) - (Y0)), P))
729
725// 730//
726// Memory section macros for devkitARM. 731// Memory section macros for devkitARM.
727// 732//
diff --git a/src/filesystem.c b/src/filesystem.c
index b60dbde..8aaa51c 100644
--- a/src/filesystem.c
+++ b/src/filesystem.c
@@ -114,7 +114,7 @@ fs_init(void) {
114 } 114 }
115 115
116 // Initialize filesystem. 116 // Initialize filesystem.
117 memset(&filesystem, 0, sizeof(FileSystem)); 117 dma_fill(&filesystem, 0, sizeof(FileSystem), 3);
118 filesystem.initialized = FS_INIT_PATTERN; 118 filesystem.initialized = FS_INIT_PATTERN;
119 for (size_t i = 0; i < FILE_INDEX_NUM; ++i) { 119 for (size_t i = 0; i < FILE_INDEX_NUM; ++i) {
120 filesystem.files[i].first_block = FS_NULL; 120 filesystem.files[i].first_block = FS_NULL;
diff --git a/src/main.c b/src/main.c
index aee68f8..35bc0cf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,7 +20,7 @@ WITH REGARD TO THIS SOFTWARE.
20#include "uxn/uxn.c" 20#include "uxn/uxn.c"
21#include "uxn/devices/ppu.h" 21#include "uxn/devices/ppu.h"
22#include "uxn/devices/ppu.c" 22#include "uxn/devices/ppu.c"
23#include "uxn/devices/apu.c" 23#include "apu.c"
24 24
25#include "text.h" 25#include "text.h"
26 26
@@ -124,44 +124,12 @@ audio_talk(Device *d, u8 b0, u8 w) {
124 } 124 }
125 } else if(b0 == 0xf) { 125 } else if(b0 == 0xf) {
126 u16 length = mempeek16(d->dat, 0xa); 126 u16 length = mempeek16(d->dat, 0xa);
127 127 u8 *data = &d->mem[mempeek16(d->dat, 0xc)];
128 // Disable the channel before updating. 128 u8 pitch = d->dat[0xf] & 0x7f;
129 c->data = NULL;
130
131 // Data.
132 c->pos = 0;
133 c->length = length;
134 c->length <<= 12; // fixed point.
135 c->data = &d->mem[mempeek16(d->dat, 0xc)];
136
137 // Volume (Mono only for now).
138 c->vol = MAX(d->dat[0xe] >> 4, d->dat[0xe] & 0xf); // 0-64
139 c->vol *= 4 / 3;
140
141 // Looping.
142 if (!(d->dat[0xf] & 0x80)) {
143 c->loop_length = c->length;
144 } else {
145 c->loop_length = 0;
146 }
147
148 // Pitch
149 c->pitch = d->dat[0xf] & 0x7f;
150
151 // Initialization.
152 u32 sampling_rate = length;
153 if (length > 256) {
154 sampling_rate = 44100;
155 }
156 c->inc = (pitch_table[c->pitch] * sampling_rate) >> 5;
157
158 u16 adsr = mempeek16(d->dat, 0x8); 129 u16 adsr = mempeek16(d->dat, 0x8);
159 build_adsr(c, adsr); 130 u32 vol = MAX(d->dat[0xe] >> 4, d->dat[0xe] & 0xf) * 4 / 3;
160 txt_position(0, 0); 131 bool loop = !(d->dat[0xf] & 0x80);
161 txt_printf("note: %d \n", c->pitch); 132 update_channel(c, data, length, pitch, adsr, vol, loop);
162 txt_printf("inc: %lu \n", c->inc);
163 txt_printf("length: %lu \n", c->length >> 12);
164 txt_printf("chan: %lu \n", d - devaudio);
165 } 133 }
166} 134}
167 135
@@ -412,7 +380,7 @@ int main(void) {
412 // irs_set(IRQ_TIMER_1, irs_stop_sample); 380 // irs_set(IRQ_TIMER_1, irs_stop_sample);
413 381
414 // Initialize VM. 382 // Initialize VM.
415 memset(&u, 0, sizeof(u)); 383 dma_fill(&u, 0, sizeof(u), 3);
416 u.ram.dat = umem; 384 u.ram.dat = umem;
417 init_uxn(&u); 385 init_uxn(&u);
418 386