| ... | ... |
@@ -43,11 +43,9 @@ BRK |
| 43 | 43 |
~Time.second ~current.second NEQ #01 JNZ BRK |
| 44 | 44 |
~Time.second =current.second |
| 45 | 45 |
|
| 46 |
- ~Time.second #03 AND ^$no-sound JNZ |
|
| 47 |
- #ffff =Audio.ch1adsr |
|
| 46 |
+ #1444 =Audio.ch1adsr |
|
| 48 | 47 |
~Time.second #1d ADD =Audio.ch1pitch |
| 49 |
- #ff =Audio.ch1vol |
|
| 50 |
- $no-sound |
|
| 48 |
+ ~Time.second #03 AND #4b MUL #0f ADD =Audio.ch1vol |
|
| 51 | 49 |
|
| 52 | 50 |
( clear ) |
| 53 | 51 |
#0080 SCALEX #0080 SCALEY ~needles.sx ~needles.sy #00 ,draw-line JSR2 |
| ... | ... |
@@ -51,26 +51,29 @@ Uint8 font[][8] = {
|
| 51 | 51 |
|
| 52 | 52 |
#define SAMPLE_FREQUENCY 48000 |
| 53 | 53 |
|
| 54 |
-static Uint32 note_periods[12] = { /* middle C (C4) is note 60 */
|
|
| 55 |
- (Uint32) 0xfa7e * SAMPLE_FREQUENCY, /* C-1 */ |
|
| 56 |
- (Uint32) 0xec6f * SAMPLE_FREQUENCY, |
|
| 57 |
- (Uint32) 0xdf2a * SAMPLE_FREQUENCY, /* D-1 */ |
|
| 58 |
- (Uint32) 0xd2a4 * SAMPLE_FREQUENCY, |
|
| 59 |
- (Uint32) 0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */ |
|
| 60 |
- (Uint32) 0xbba8 * SAMPLE_FREQUENCY, /* F-1 */ |
|
| 61 |
- (Uint32) 0xb120 * SAMPLE_FREQUENCY, |
|
| 62 |
- (Uint32) 0xa72f * SAMPLE_FREQUENCY, /* G-1 */ |
|
| 63 |
- (Uint32) 0x9dcd * SAMPLE_FREQUENCY, |
|
| 64 |
- (Uint32) 0x94f2 * SAMPLE_FREQUENCY, /* A-1 */ |
|
| 65 |
- (Uint32) 0x8c95 * SAMPLE_FREQUENCY, |
|
| 66 |
- (Uint32) 0x84b2 * SAMPLE_FREQUENCY /* B-1 */ |
|
| 54 |
+static Uint32 note_periods[12] = {
|
|
| 55 |
+ /* middle C (C4) is note 60 */ |
|
| 56 |
+ (Uint32)0xfa7e * SAMPLE_FREQUENCY, /* C-1 */ |
|
| 57 |
+ (Uint32)0xec6f * SAMPLE_FREQUENCY, |
|
| 58 |
+ (Uint32)0xdf2a * SAMPLE_FREQUENCY, /* D-1 */ |
|
| 59 |
+ (Uint32)0xd2a4 * SAMPLE_FREQUENCY, |
|
| 60 |
+ (Uint32)0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */ |
|
| 61 |
+ (Uint32)0xbba8 * SAMPLE_FREQUENCY, /* F-1 */ |
|
| 62 |
+ (Uint32)0xb120 * SAMPLE_FREQUENCY, |
|
| 63 |
+ (Uint32)0xa72f * SAMPLE_FREQUENCY, /* G-1 */ |
|
| 64 |
+ (Uint32)0x9dcd * SAMPLE_FREQUENCY, |
|
| 65 |
+ (Uint32)0x94f2 * SAMPLE_FREQUENCY, /* A-1 */ |
|
| 66 |
+ (Uint32)0x8c95 * SAMPLE_FREQUENCY, |
|
| 67 |
+ (Uint32)0x84b2 * SAMPLE_FREQUENCY /* B-1 */ |
|
| 67 | 68 |
}; |
| 68 | 69 |
|
| 69 |
-static struct audio_channel {
|
|
| 70 |
+typedef struct audio_channel {
|
|
| 70 | 71 |
Uint32 period, count; |
| 71 | 72 |
Sint32 age, a, d, s, r; |
| 72 |
- Sint16 volume, value; |
|
| 73 |
-} channels[4]; |
|
| 73 |
+ Sint16 value[2]; |
|
| 74 |
+ Sint8 volume[2], phase; |
|
| 75 |
+} Channel; |
|
| 76 |
+Channel channels[4]; |
|
| 74 | 77 |
|
| 75 | 78 |
static SDL_Window *gWindow; |
| 76 | 79 |
static SDL_Renderer *gRenderer; |
| ... | ... |
@@ -236,39 +239,58 @@ togglezoom(Uxn *u) |
| 236 | 239 |
redraw(pixels, u); |
| 237 | 240 |
} |
| 238 | 241 |
|
| 242 |
+Sint16 |
|
| 243 |
+audio_envelope(Channel *c) {
|
|
| 244 |
+ if (c->age < c->a) |
|
| 245 |
+ return 0x0888 * c->age / c->a; |
|
| 246 |
+ else if (c->age < c->d) |
|
| 247 |
+ return 0x0444 * (2 * c->d - c->a - c->age) / (c->d - c->a); |
|
| 248 |
+ else if (c->age < c->s) |
|
| 249 |
+ return 0x0444; |
|
| 250 |
+ else if (c->age < c->r) |
|
| 251 |
+ return 0x0444 * (c->r - c->age) / (c->r - c->s); |
|
| 252 |
+ else |
|
| 253 |
+ return 0x0000; |
|
| 254 |
+} |
|
| 255 |
+ |
|
| 239 | 256 |
void |
| 240 | 257 |
audio_callback(void* userdata, Uint8* stream, int len) {
|
| 241 | 258 |
Sint16 *samples = (Sint16 *) stream; |
| 242 | 259 |
int i, j; |
| 243 |
- len >>= 1; /* use len for number of samples, not bytes */ |
|
| 244 |
- for (j = 0; j < len; ++j) samples[j] = 0; |
|
| 260 |
+ len >>= 2; /* use len for number of samples, not bytes */ |
|
| 261 |
+ for (j = len * 2 - 1; j >= 0; --j) samples[j] = 0; |
|
| 245 | 262 |
for (i = 0; i < 4; ++i) {
|
| 246 |
- struct audio_channel *c = &channels[i]; |
|
| 247 |
- if (!c->volume) continue; |
|
| 263 |
+ Channel *c = &channels[i]; |
|
| 248 | 264 |
if (c->period < (1 << 20)) continue; |
| 249 | 265 |
for (j = 0; j < len; ++j) {
|
| 250 | 266 |
c->age += 1; |
| 251 | 267 |
c->count += 1 << 20; |
| 252 | 268 |
while (c->count > c->period) {
|
| 253 |
- int mul = c->value < 0 ? c->volume : -c->volume; |
|
| 269 |
+ Sint16 mul; |
|
| 254 | 270 |
c->count -= c->period; |
| 255 |
- if (c->age < c->a) |
|
| 256 |
- c->value = mul * c->age / c->a; |
|
| 257 |
- else if (c->age < c->d) |
|
| 258 |
- c->value = mul * (2 * c->d - c->a - c->age) / 2 / (c->d - c->a); |
|
| 259 |
- else if (c->age < c->s) |
|
| 260 |
- c->value = mul / 2; |
|
| 261 |
- else if (c->age < c->r) |
|
| 262 |
- c->value = mul * (c->r - c->age) / 2 / (c->r - c->s); |
|
| 263 |
- else |
|
| 264 |
- c->volume = c->value = 0; |
|
| 271 |
+ c->phase = !c->phase; |
|
| 272 |
+ mul = (c->phase * 2 - 1) * audio_envelope(c); |
|
| 273 |
+ c->value[0] = mul * c->volume[0]; |
|
| 274 |
+ c->value[1] = mul * c->volume[1]; |
|
| 265 | 275 |
} |
| 266 |
- samples[j] += c->value; |
|
| 276 |
+ samples[j * 2] += c->value[0]; |
|
| 277 |
+ samples[j * 2 + 1] += c->value[1]; |
|
| 267 | 278 |
} |
| 268 | 279 |
} |
| 269 | 280 |
(void) userdata; |
| 270 | 281 |
} |
| 271 | 282 |
|
| 283 |
+void |
|
| 284 |
+silence(void) {
|
|
| 285 |
+ int i; |
|
| 286 |
+ for (i = 0; i < 4; ++i) {
|
|
| 287 |
+ Channel *c = &channels[i]; |
|
| 288 |
+ c->volume[0] = 0; |
|
| 289 |
+ c->volume[1] = 0; |
|
| 290 |
+ c->period = 0; |
|
| 291 |
+ } |
|
| 292 |
+} |
|
| 293 |
+ |
|
| 272 | 294 |
void |
| 273 | 295 |
quit(void) |
| 274 | 296 |
{
|
| ... | ... |
@@ -301,11 +323,12 @@ init(void) |
| 301 | 323 |
if(!(pixels = (Uint32 *)malloc(WIDTH * HEIGHT * sizeof(Uint32)))) |
| 302 | 324 |
return error("Pixels", "Failed to allocate memory");
|
| 303 | 325 |
clear(pixels); |
| 326 |
+ silence(); |
|
| 304 | 327 |
SDL_StartTextInput(); |
| 305 | 328 |
SDL_ShowCursor(SDL_DISABLE); |
| 306 | 329 |
as.freq = SAMPLE_FREQUENCY; |
| 307 | 330 |
as.format = AUDIO_S16; |
| 308 |
- as.channels = 1; |
|
| 331 |
+ as.channels = 2; |
|
| 309 | 332 |
as.callback = audio_callback; |
| 310 | 333 |
as.samples = 2048; |
| 311 | 334 |
audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0); |
| ... | ... |
@@ -474,17 +497,18 @@ audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) |
| 474 | 497 |
{
|
| 475 | 498 |
Uint8 *m = u->ram.dat; |
| 476 | 499 |
if (b0 & 1) {
|
| 477 |
- Uint16 channel_addr = ptr + (b0 & 0x6); |
|
| 478 |
- struct audio_channel *c = &channels[(b0 & 0x6) >> 1]; |
|
| 500 |
+ Uint16 addr = ptr + (b0 & 0x6); |
|
| 501 |
+ Channel *c = &channels[(b0 & 0x6) >> 1]; |
|
| 479 | 502 |
SDL_LockAudioDevice(audio_id); |
| 480 |
- c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12); |
|
| 503 |
+ c->period = note_periods[m[addr + 8] % 12] >> (m[addr + 8] / 12); |
|
| 481 | 504 |
c->count %= c->period; |
| 482 |
- c->volume = m[channel_addr + 9] << 5; |
|
| 505 |
+ c->volume[0] = (m[addr + 9] >> 4) & 0xf; |
|
| 506 |
+ c->volume[1] = m[addr + 9] & 0xf; |
|
| 483 | 507 |
c->age = 0; |
| 484 |
- c->a = ((m[channel_addr] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4); |
|
| 485 |
- c->d = c->a + (m[channel_addr] & 0xf) * (SAMPLE_FREQUENCY >> 4); |
|
| 486 |
- c->s = c->d + ((m[channel_addr + 1] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4); |
|
| 487 |
- c->r = c->s + (m[channel_addr + 1] & 0xf) * (SAMPLE_FREQUENCY >> 4); |
|
| 508 |
+ c->a = (SAMPLE_FREQUENCY >> 4) * ((m[addr] >> 4) & 0xf); |
|
| 509 |
+ c->d = c->a + (SAMPLE_FREQUENCY >> 4) * (m[addr] & 0xf); |
|
| 510 |
+ c->s = c->d + (SAMPLE_FREQUENCY >> 4) * ((m[addr + 1] >> 4) & 0xf); |
|
| 511 |
+ c->r = c->s + (SAMPLE_FREQUENCY >> 4) * (m[addr + 1] & 0xf); |
|
| 488 | 512 |
SDL_UnlockAudioDevice(audio_id); |
| 489 | 513 |
} |
| 490 | 514 |
return b1; |