Implemented ADSR envelopes.
This commit is contained in:
commit
6be1ab909d
|
@ -11,14 +11,13 @@
|
||||||
;needles { hx 2 hy 2 mx 2 my 2 sx 2 sy 2 }
|
;needles { hx 2 hy 2 mx 2 my 2 sx 2 sy 2 }
|
||||||
;line { x0 2 y0 2 x 2 y 2 sx 2 sy 2 dx 2 dy 2 e1 2 e2 2 }
|
;line { x0 2 y0 2 x 2 y 2 sx 2 sy 2 dx 2 dy 2 e1 2 e2 2 }
|
||||||
;color { byte 1 }
|
;color { byte 1 }
|
||||||
;ding { volume 1 }
|
|
||||||
|
|
||||||
( devices )
|
( devices )
|
||||||
|
|
||||||
|0100 ;Console { pad 8 char 1 byte 1 short 2 }
|
|0100 ;Console { pad 8 char 1 byte 1 short 2 }
|
||||||
|0110 ;Screen { width 2 height 2 pad 4 x 2 y 2 color 1 }
|
|0110 ;Screen { width 2 height 2 pad 4 x 2 y 2 color 1 }
|
||||||
|0120 ;Sprite { pad 8 x 2 y 2 addr 2 color 1 }
|
|0120 ;Sprite { pad 8 x 2 y 2 addr 2 color 1 }
|
||||||
|0170 ;Audio { ch1asdr 2 ch2asdr 2 ch3asdr 2 ch4asdr 2 ch1pitch 1 ch1vol 1 ch2pitch 1 ch2vol 1 ch3pitch 1 ch3vol 1 ch4pitch 1 ch4vol 1 }
|
|0170 ;Audio { ch1adsr 2 ch2adsr 2 ch3adsr 2 ch4adsr 2 ch1pitch 1 ch1vol 1 ch2pitch 1 ch2vol 1 ch3pitch 1 ch3vol 1 ch4pitch 1 ch4vol 1 }
|
||||||
|0190 ;Time { year 2 month 1 day 1 hour 1 minute 1 second 1 dow 1 doy 2 isdst 1 get 1 }
|
|0190 ;Time { year 2 month 1 day 1 hour 1 minute 1 second 1 dow 1 doy 2 isdst 1 get 1 }
|
||||||
|01F0 ;System { pad 8 r 2 g 2 b 2 }
|
|01F0 ;System { pad 8 r 2 g 2 b 2 }
|
||||||
|
|
||||||
|
@ -38,20 +37,17 @@ BRK
|
||||||
|
|
||||||
@FRAME
|
@FRAME
|
||||||
|
|
||||||
~ding.volume
|
|
||||||
DUP #00 EQU ^$keep JNZ
|
|
||||||
DUP #04 SUB =ding.volume
|
|
||||||
$keep
|
|
||||||
=Audio.ch1vol
|
|
||||||
|
|
||||||
#00 =Time.get
|
#00 =Time.get
|
||||||
|
|
||||||
( only draw once per second )
|
( only draw once per second )
|
||||||
~Time.second ~current.second NEQ #01 JNZ BRK
|
~Time.second ~current.second NEQ #01 JNZ BRK
|
||||||
~Time.second =current.second
|
~Time.second =current.second
|
||||||
|
|
||||||
|
~Time.second #03 AND ^$no-sound JNZ
|
||||||
|
#ffff =Audio.ch1adsr
|
||||||
~Time.second #1d ADD =Audio.ch1pitch
|
~Time.second #1d ADD =Audio.ch1pitch
|
||||||
#fc =ding.volume
|
#ff =Audio.ch1vol
|
||||||
|
$no-sound
|
||||||
|
|
||||||
( clear )
|
( clear )
|
||||||
#0080 SCALEX #0080 SCALEY ~needles.sx ~needles.sy #00 ,draw-line JSR2
|
#0080 SCALEX #0080 SCALEY ~needles.sx ~needles.sy #00 ,draw-line JSR2
|
||||||
|
|
|
@ -51,26 +51,25 @@ Uint8 font[][8] = {
|
||||||
|
|
||||||
#define SAMPLE_FREQUENCY 48000
|
#define SAMPLE_FREQUENCY 48000
|
||||||
|
|
||||||
static Uint32 note_periods[12] = {
|
static Uint32 note_periods[12] = { /* middle C (C4) is note 60 */
|
||||||
/* middle C (C4) is note 60 */
|
(Uint32) 0xfa7e * SAMPLE_FREQUENCY, /* C-1 */
|
||||||
(Uint32)0xfa7e * SAMPLE_FREQUENCY, /* C-1 */
|
(Uint32) 0xec6f * SAMPLE_FREQUENCY,
|
||||||
(Uint32)0xec6f * SAMPLE_FREQUENCY,
|
(Uint32) 0xdf2a * SAMPLE_FREQUENCY, /* D-1 */
|
||||||
(Uint32)0xdf2a * SAMPLE_FREQUENCY, /* D-1 */
|
(Uint32) 0xd2a4 * SAMPLE_FREQUENCY,
|
||||||
(Uint32)0xd2a4 * SAMPLE_FREQUENCY,
|
(Uint32) 0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */
|
||||||
(Uint32)0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */
|
(Uint32) 0xbba8 * SAMPLE_FREQUENCY, /* F-1 */
|
||||||
(Uint32)0xbba8 * SAMPLE_FREQUENCY, /* F-1 */
|
(Uint32) 0xb120 * SAMPLE_FREQUENCY,
|
||||||
(Uint32)0xb120 * SAMPLE_FREQUENCY,
|
(Uint32) 0xa72f * SAMPLE_FREQUENCY, /* G-1 */
|
||||||
(Uint32)0xa72f * SAMPLE_FREQUENCY, /* G-1 */
|
(Uint32) 0x9dcd * SAMPLE_FREQUENCY,
|
||||||
(Uint32)0x9dcd * SAMPLE_FREQUENCY,
|
(Uint32) 0x94f2 * SAMPLE_FREQUENCY, /* A-1 */
|
||||||
(Uint32)0x94f2 * SAMPLE_FREQUENCY, /* A-1 */
|
(Uint32) 0x8c95 * SAMPLE_FREQUENCY,
|
||||||
(Uint32)0x8c95 * SAMPLE_FREQUENCY,
|
(Uint32) 0x84b2 * SAMPLE_FREQUENCY /* B-1 */
|
||||||
(Uint32)0x84b2 * SAMPLE_FREQUENCY /* B-1 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct audio_channel {
|
static struct audio_channel {
|
||||||
Uint32 period, count;
|
Uint32 period, count;
|
||||||
int value;
|
Sint32 age, a, d, s, r;
|
||||||
Sint16 volume;
|
Sint16 volume, value;
|
||||||
} channels[4];
|
} channels[4];
|
||||||
|
|
||||||
static SDL_Window *gWindow;
|
static SDL_Window *gWindow;
|
||||||
|
@ -238,26 +237,36 @@ togglezoom(Uxn *u)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_callback(void *userdata, Uint8 *stream, int len)
|
audio_callback(void* userdata, Uint8* stream, int len) {
|
||||||
{
|
Sint16 *samples = (Sint16 *) stream;
|
||||||
Sint16 *samples = (Sint16 *)stream;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
len >>= 1; /* use len for number of samples, not bytes */
|
len >>= 1; /* use len for number of samples, not bytes */
|
||||||
for(j = 0; j < len; ++j) samples[j] = 0;
|
for (j = 0; j < len; ++j) samples[j] = 0;
|
||||||
for(i = 0; i < 4; ++i) {
|
for (i = 0; i < 4; ++i) {
|
||||||
struct audio_channel *c = &channels[i];
|
struct audio_channel *c = &channels[i];
|
||||||
if(!c->volume) continue;
|
if (!c->volume) continue;
|
||||||
if(c->period < (1 << 20)) continue;
|
if (c->period < (1 << 20)) continue;
|
||||||
for(j = 0; j < len; ++j) {
|
for (j = 0; j < len; ++j) {
|
||||||
|
c->age += 1;
|
||||||
c->count += 1 << 20;
|
c->count += 1 << 20;
|
||||||
while(c->count > c->period) {
|
while (c->count > c->period) {
|
||||||
c->value = !c->value;
|
int mul = c->value < 0 ? c->volume : -c->volume;
|
||||||
c->count -= c->period;
|
c->count -= c->period;
|
||||||
|
if (c->age < c->a)
|
||||||
|
c->value = mul * c->age / c->a;
|
||||||
|
else if (c->age < c->d)
|
||||||
|
c->value = mul * (2 * c->d - c->a - c->age) / 2 / (c->d - c->a);
|
||||||
|
else if (c->age < c->s)
|
||||||
|
c->value = mul / 2;
|
||||||
|
else if (c->age < c->r)
|
||||||
|
c->value = mul * (c->r - c->age) / 2 / (c->r - c->s);
|
||||||
|
else
|
||||||
|
c->volume = c->value = 0;
|
||||||
}
|
}
|
||||||
samples[j] += (c->value * 2 - 1) * c->volume;
|
samples[j] += c->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void)userdata;
|
(void) userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -464,13 +473,18 @@ Uint8
|
||||||
audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||||
{
|
{
|
||||||
Uint8 *m = u->ram.dat;
|
Uint8 *m = u->ram.dat;
|
||||||
if(b0 & 1) {
|
if (b0 & 1) {
|
||||||
Uint16 channel_addr = ptr + (b0 & 0x6);
|
Uint16 channel_addr = ptr + (b0 & 0x6);
|
||||||
struct audio_channel *c = &channels[(b0 & 0x6) >> 1];
|
struct audio_channel *c = &channels[(b0 & 0x6) >> 1];
|
||||||
SDL_LockAudioDevice(audio_id);
|
SDL_LockAudioDevice(audio_id);
|
||||||
c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12);
|
c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12);
|
||||||
c->count %= c->period;
|
c->count %= c->period;
|
||||||
c->volume = m[channel_addr + 9] << 5;
|
c->volume = m[channel_addr + 9] << 5;
|
||||||
|
c->age = 0;
|
||||||
|
c->a = ((m[channel_addr] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4);
|
||||||
|
c->d = c->a + (m[channel_addr] & 0xf) * (SAMPLE_FREQUENCY >> 4);
|
||||||
|
c->s = c->d + ((m[channel_addr + 1] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4);
|
||||||
|
c->r = c->s + (m[channel_addr + 1] & 0xf) * (SAMPLE_FREQUENCY >> 4);
|
||||||
SDL_UnlockAudioDevice(audio_id);
|
SDL_UnlockAudioDevice(audio_id);
|
||||||
}
|
}
|
||||||
return b1;
|
return b1;
|
||||||
|
|
Loading…
Reference in New Issue