... | ... |
@@ -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; |