audio.c (8378B)
1 #include "../uxn.h" 2 #include "audio.h" 3 #include <stdbool.h> 4 #include <string.h> 5 6 /* 7 Copyright (c) 2021-2023 Devine Lu Linvega, Andrew Alderwick, Bad Diode 8 9 Permission to use, copy, modify, and distribute this software for any 10 purpose with or without fee is hereby granted, provided that the above 11 copyright notice and this permission notice appear in all copies. 12 13 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 WITH REGARD TO THIS SOFTWARE. 15 */ 16 17 #define SOUND_TIMER (AUDIO_BUFSIZE / SAMPLE_FREQUENCY * 1000.0f) 18 #define XFADE_SAMPLES 100 19 #define INTERPOL_METHOD 1 20 21 typedef enum EnvStage { 22 ENV_ATTACK = (1 << 0), 23 ENV_DECAY = (1 << 1), 24 ENV_SUSTAIN = (1 << 2), 25 ENV_RELEASE = (1 << 3), 26 } EnvStage; 27 28 typedef struct Envelope { 29 float a; 30 float d; 31 float s; 32 float r; 33 float vol; 34 EnvStage stage; 35 } Envelope; 36 37 typedef struct Sample { 38 Uint8 *data; 39 float len; 40 float pos; 41 float inc; 42 float loop; 43 Uint8 pitch; 44 Envelope env; 45 } Sample; 46 47 typedef struct AudioChannel { 48 Sample sample; 49 Sample next_sample; 50 bool xfade; 51 float duration; 52 float vol_l; 53 float vol_r; 54 } AudioChannel; 55 56 AudioChannel channel[POLYPHONY]; 57 58 /* clang-format off */ 59 60 const float tuning[109] = { 61 0.00058853f, 0.00062352f, 0.00066060f, 0.00069988f, 0.00074150f, 62 0.00078559f, 0.00083230f, 0.00088179f, 0.00093423f, 0.00098978f, 63 0.00104863f, 0.00111099f, 0.00117705f, 0.00124704f, 0.00132120f, 64 0.00139976f, 0.00148299f, 0.00157118f, 0.00166460f, 0.00176359f, 65 0.00186845f, 0.00197956f, 0.00209727f, 0.00222198f, 0.00235410f, 66 0.00249409f, 0.00264239f, 0.00279952f, 0.00296599f, 0.00314235f, 67 0.00332921f, 0.00352717f, 0.00373691f, 0.00395912f, 0.00419454f, 68 0.00444396f, 0.00470821f, 0.00498817f, 0.00528479f, 0.00559904f, 69 0.00593197f, 0.00628471f, 0.00665841f, 0.00705434f, 0.00747382f, 70 0.00791823f, 0.00838908f, 0.00888792f, 0.00941642f, 0.00997635f, 71 0.01056957f, 0.01119807f, 0.01186395f, 0.01256941f, 0.01331683f, 72 0.01410869f, 0.01494763f, 0.01583647f, 0.01677815f, 0.01777583f, 73 0.01883284f, 0.01995270f, 0.02113915f, 0.02239615f, 0.02372789f, 74 0.02513882f, 0.02663366f, 0.02821738f, 0.02989527f, 0.03167293f, 75 0.03355631f, 0.03555167f, 0.03766568f, 0.03990540f, 0.04227830f, 76 0.04479229f, 0.04745578f, 0.05027765f, 0.05326731f, 0.05643475f, 77 0.05979054f, 0.06334587f, 0.06711261f, 0.07110333f, 0.07533136f, 78 0.07981079f, 0.08455659f, 0.08958459f, 0.09491156f, 0.10055530f, 79 0.10653463f, 0.11286951f, 0.11958108f, 0.12669174f, 0.13422522f, 80 0.14220667f, 0.15066272f, 0.15962159f, 0.16911318f, 0.17916918f, 81 0.18982313f, 0.20111060f, 0.21306926f, 0.22573902f, 0.23916216f, 82 0.25338348f, 0.26845044f, 0.28441334f, 0.30132544f, 83 }; 84 85 /* clang-format on */ 86 87 void 88 env_on(Envelope *env) 89 { 90 env->stage = ENV_ATTACK; 91 env->vol = 0.0f; 92 if(env->a > 0) { 93 env->a = (SOUND_TIMER / AUDIO_BUFSIZE) / env->a; 94 } else if(env->stage == ENV_ATTACK) { 95 env->stage = ENV_DECAY; 96 env->vol = 1.0f; 97 } 98 if(env->d < 10.0f) { 99 env->d = 10.0f; 100 } 101 env->d = (SOUND_TIMER / AUDIO_BUFSIZE) / env->d; 102 if(env->r < 10.0f) { 103 env->r = 10.0f; 104 } 105 env->r = (SOUND_TIMER / AUDIO_BUFSIZE) / env->r; 106 } 107 108 void 109 env_off(Envelope *env) 110 { 111 env->stage = ENV_RELEASE; 112 } 113 114 void 115 note_on(AudioChannel *channel, float duration, Uint8 *data, Uint16 len, Uint8 vol, Uint8 attack, Uint8 decay, Uint8 sustain, Uint8 release, Uint8 pitch, bool loop) 116 { 117 channel->duration = duration; 118 channel->vol_l = (vol >> 4) / 15.0f; 119 channel->vol_r = (vol & 0xf) / 15.0f; 120 121 Sample sample = {0}; 122 sample.data = data; 123 sample.len = len; 124 sample.pos = 0; 125 sample.env.a = attack * 64.0f; 126 sample.env.d = decay * 64.0f; 127 sample.env.s = sustain / 16.0f; 128 sample.env.r = release * 64.0f; 129 if(loop) { 130 sample.loop = len; 131 } else { 132 sample.loop = 0; 133 } 134 env_on(&sample.env); 135 float sample_rate = 44100 / 261.60; 136 if(len <= 256) { 137 sample_rate = len; 138 } 139 const float *inc = &tuning[pitch - 20]; 140 sample.inc = *(inc)*sample_rate; 141 142 channel->next_sample = sample; 143 channel->xfade = true; 144 } 145 146 void 147 note_off(AudioChannel *channel, float duration) 148 { 149 channel->duration = duration; 150 env_off(&channel->sample.env); 151 } 152 153 void 154 env_advance(Envelope *env) 155 { 156 switch(env->stage) { 157 case ENV_ATTACK: { 158 env->vol += env->a; 159 if(env->vol >= 1.0f) { 160 env->stage = ENV_DECAY; 161 env->vol = 1.0f; 162 } 163 } break; 164 case ENV_DECAY: { 165 env->vol -= env->d; 166 if(env->vol <= env->s || env->d <= 0) { 167 env->stage = ENV_SUSTAIN; 168 env->vol = env->s; 169 } 170 } break; 171 case ENV_SUSTAIN: { 172 env->vol = env->s; 173 } break; 174 case ENV_RELEASE: { 175 if(env->vol <= 0 || env->r <= 0) { 176 env->vol = 0; 177 } else { 178 env->vol -= env->r; 179 } 180 } break; 181 } 182 } 183 184 float 185 interpolate_sample(Uint8 *data, Uint16 len, float pos) 186 { 187 #if INTERPOL_METHOD == 0 188 return data[(int)pos]; 189 190 #elif INTERPOL_METHOD == 1 191 float x = pos; 192 int x0 = (int)x; 193 int x1 = (x0 + 1); 194 float y0 = data[x0]; 195 float y1 = data[x1 % len]; 196 x = x - x0; 197 float y = y0 + x * (y1 - y0); 198 return y; 199 200 #elif INTERPOL_METHOD == 2 201 float x = pos; 202 int x0 = x - 1; 203 int x1 = x; 204 int x2 = x + 1; 205 int x3 = x + 2; 206 float y0 = data[x0 % len]; 207 float y1 = data[x1]; 208 float y2 = data[x2 % len]; 209 float y3 = data[x3 % len]; 210 x = x - x1; 211 float c0 = y1; 212 float c1 = 0.5f * (y2 - y0); 213 float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3; 214 float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0); 215 return ((c3 * x + c2) * x + c1) * x + c0; 216 #endif 217 } 218 219 Sint16 220 next_sample(Sample *sample) 221 { 222 if(sample->pos >= sample->len) { 223 if(sample->loop == 0) { 224 sample->data = 0; 225 return 0; 226 } 227 while(sample->pos >= sample->len) { 228 sample->pos -= sample->loop; 229 } 230 } 231 232 float val = interpolate_sample(sample->data, sample->len, sample->pos); 233 val *= sample->env.vol; 234 Sint8 next = (Sint8)0x80 ^ (Uint8)val; 235 236 sample->pos += sample->inc; 237 env_advance(&sample->env); 238 return next; 239 } 240 241 void 242 audio_handler(void *ctx, Uint8 *out_stream, int len) 243 { 244 Sint16 *stream = (Sint16 *)out_stream; 245 memset(stream, 0x00, len); 246 247 int n; 248 for(n = 0; n < POLYPHONY; n++) { 249 Uint8 device = (3 + n) << 4; 250 Uxn *u = (Uxn *)ctx; 251 Uint8 *addr = &u->dev[device]; 252 if(channel[n].duration <= 0 && PEEK2(addr)) { 253 uxn_eval(u, PEEK2(addr)); 254 } 255 channel[n].duration -= SOUND_TIMER; 256 257 int x = 0; 258 if(channel[n].xfade) { 259 float delta = 1.0f / (XFADE_SAMPLES * 2); 260 while(x < XFADE_SAMPLES * 2) { 261 float alpha = x * delta; 262 float beta = 1.0f - alpha; 263 Sint16 next_a = next_sample(&channel[n].next_sample); 264 Sint16 next_b = 0; 265 if(channel[n].sample.data != 0) { 266 next_b = next_sample(&channel[n].sample); 267 } 268 Sint16 next = alpha * next_a + beta * next_b; 269 stream[x++] += next * channel[n].vol_l; 270 stream[x++] += next * channel[n].vol_r; 271 } 272 channel[n].sample = channel[n].next_sample; 273 channel[n].xfade = false; 274 } 275 Sample *sample = &channel[n].sample; 276 while(x < len / 2) { 277 if(sample->data == 0) { 278 break; 279 } 280 Sint16 next = next_sample(sample); 281 stream[x++] += next * channel[n].vol_l; 282 stream[x++] += next * channel[n].vol_r; 283 } 284 } 285 int i; 286 for(i = 0; i < len / 2; i++) { 287 stream[i] <<= 6; 288 } 289 } 290 291 float 292 calc_duration(Uint16 len, Uint8 pitch) 293 { 294 float scale = tuning[pitch - 20] / tuning[0x3c - 20]; 295 return len / (scale * 44.1f); 296 } 297 298 void 299 audio_start(int idx, Uint8 *d, Uxn *u) 300 { 301 Uint16 dur = PEEK2(d + 0x5); 302 Uint8 off = d[0xf] == 0x00; 303 Uint16 len = PEEK2(d + 0xa); 304 Uint8 pitch = d[0xf] & 0x7f; 305 if(pitch < 20) { 306 pitch = 20; 307 } 308 float duration = dur > 0 ? dur : calc_duration(len, pitch); 309 310 if(!off) { 311 Uint16 addr = PEEK2(d + 0xc); 312 Uint8 *data = &u->ram[addr]; 313 Uint8 volume = d[0xe]; 314 bool loop = !(d[0xf] & 0x80); 315 Uint16 adsr = PEEK2(d + 0x8); 316 Uint8 attack = (adsr >> 12) & 0xF; 317 Uint8 decay = (adsr >> 8) & 0xF; 318 Uint8 sustain = (adsr >> 4) & 0xF; 319 Uint8 release = (adsr >> 0) & 0xF; 320 note_on(&channel[idx], duration, data, len, volume, attack, decay, sustain, release, pitch, loop); 321 } else { 322 note_off(&channel[idx], duration); 323 } 324 } 325 326 Uint8 327 audio_get_vu(int instance) 328 { 329 return channel[instance].sample.env.vol * 255.0f; 330 } 331 332 Uint16 333 audio_get_position(int instance) 334 { 335 return channel[instance].sample.pos; 336 } 337 338 Uint8 339 audio_dei(int instance, Uint8 *d, Uint8 port) 340 { 341 switch(port) { 342 case 0x2: return audio_get_position(instance) >> 8; 343 case 0x3: return audio_get_position(instance); 344 case 0x4: return audio_get_vu(instance); 345 } 346 return d[port]; 347 }