From 77399aa2b0e70c7712b1720300b202a9fdced1e3 Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 6 Jul 2026 16:36:57 +0900 Subject: Sound now working --- src/audio.c | 6 +-- src/audio.h | 10 ++-- src/main.c | 2 +- src/spec.c | 168 ++++++++++++++++++++++++++++++++++++------------------------ src/spec.h | 4 ++ 5 files changed, 111 insertions(+), 79 deletions(-) diff --git a/src/audio.c b/src/audio.c index 7eef433..e55520b 100644 --- a/src/audio.c +++ b/src/audio.c @@ -37,11 +37,11 @@ static SDL_AudioDeviceID device; /* ---------------------------------------- INTERFACES */ -int AUDIOInit(void) +int AUDIOInit(int frequency) { SDL_AudioSpec spec = {0}; - spec.freq = SAMPLE_RATE; + spec.freq = frequency; spec.format = AUDIO_S8; spec.channels = 1; spec.samples = 4096; @@ -56,7 +56,7 @@ int AUDIOInit(void) return device != 0; } -void AUDIOQueue(Uint8 *buffer, size_t len) +void AUDIOQueue(Sint8 *buffer, size_t len) { if (device != 0) { diff --git a/src/audio.h b/src/audio.h index b799abd..77fd67b 100644 --- a/src/audio.h +++ b/src/audio.h @@ -30,10 +30,6 @@ #include #include -/* The sample rate -*/ -#define SAMPLE_RATE 48000 - /* ---------------------------------------- INTERFACES */ @@ -41,14 +37,14 @@ audio. All other interfaces will silently do nothing if the device can't be opened. */ -int AUDIOInit(void); +int AUDIOInit(int frequency); -/* Add the passed buffer to the sound queue. It is an unsigned 8-bit mono +/* Add the passed buffer to the sound queue. It is a signed 8-bit mono sample which will be converted as appropriate by the audio interface. Well turns out SDL does that for you. */ -void AUDIOQueue(Uint8 *buffer, size_t len); +void AUDIOQueue(Sint8 *buffer, size_t len); #endif diff --git a/src/main.c b/src/main.c index 1766cd1..930a087 100644 --- a/src/main.c +++ b/src/main.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) if (IConfig(CONF_SOUND)) { - if (!AUDIOInit()) + if (!AUDIOInit(SPECAudioFrequency())) { fprintf(stderr, "warning: couldn't initialise audio\n"); } diff --git a/src/spec.c b/src/spec.c index 6393ef2..d1d7fb2 100644 --- a/src/spec.c +++ b/src/spec.c @@ -206,13 +206,23 @@ static const MatrixMap keymap[]= {SDLK_UNKNOWN, 0,0,0,0}, }; -static size_t sample_buff_sz; -static double cycles_per_sample; +/* Timers +*/ +#define SCANLINE_TIMER eZ80_Timer_1 +#define AUDIO_TIMER eZ80_Timer_2 + +/* Sound emulation +*/ +#define AUDIO_FRAMES 2 +#define AUDIO_SCALE 6 /* This is used as a shift value */ +#define AUDIO_CYCLES (AUDIO_FRAMES * FRAME_CYCLES) + +static size_t audio_sample_sz; typedef struct SoundRecord { Z80Val cycle; - Uint8 level; + Sint8 level; struct SoundRecord *next; } SoundRecord; @@ -220,7 +230,7 @@ static struct { SoundRecord *head; SoundRecord *tail; - Uint8 last_level; + Sint8 last_level; } sound; /* ---------------------------------------- DEBUG FUNCTIONS @@ -271,7 +281,7 @@ static void ClearKeys(void) } } -static void AddSoundRecord(Z80Val cycle, Uint8 level) +static void AddSoundRecord(Z80Val cycle, Sint8 level) { SoundRecord *new = Malloc(sizeof *new); @@ -496,14 +506,76 @@ static int EDCallback(Z80 *z80, Z80Val data) return TRUE; } +static void CheckSound(Z80 *z80) +{ + if (IConfig(CONF_SOUND)) + { + if (Z80GetTimer(z80, AUDIO_TIMER) > AUDIO_CYCLES) + { + static Sint8 *sample; + SoundRecord *current = sound.head; + int offset = 0; -static int CheckTimers(Z80 *z80, Z80Val val) + sample = Malloc(audio_sample_sz); + + memset(sample, 0, audio_sample_sz); + + if (current) + { + int f; + int first_offset = current->cycle >> AUDIO_SCALE; + + for(f = 0; f < first_offset; f++) + { + sample[f] = sound.last_level; + } + + while(current) + { + int next_offset; + + if (current->next) + { + next_offset = current->cycle >> AUDIO_SCALE; + } + else + { + next_offset = audio_sample_sz; + } + + for(f = offset; f < next_offset; f++) + { + sample[f] = current->level; + } + + offset = next_offset; + sound.last_level = current->level; + current = current->next; + } + } + + AUDIOQueue(sample, audio_sample_sz); + + ClearSoundRecord(); + + Z80SetTimer(z80, AUDIO_TIMER, 0); + free(sample); + } + } +} + + +static void CheckScanlines(Z80 *z80) { - if (val>SCAN_CYCLES) + Z80Val val; + + val = Z80GetTimer(z80, SCANLINE_TIMER); + + if (val > SCAN_CYCLES) { int y; - Z80ResetCycles(z80,val-SCAN_CYCLES); + Z80SetTimer(z80, SCANLINE_TIMER, val - SCAN_CYCLES); /* Increment scan line and check for frame flyback */ @@ -538,55 +610,6 @@ static int CheckTimers(Z80 *z80, Z80Val val) { selected_out_tape--; } - - if (IConfig(CONF_SOUND)) - { - Uint8 *sample = Malloc(sample_buff_sz); - SoundRecord *current = sound.head; - int offset = 0; - - memset(sample, 0, sample_buff_sz); - - if (current) - { - int f; - int first_offset = (int)(current->cycle / cycles_per_sample); - - for(f = 0; f < first_offset; f++) - { - sample[f] = sound.last_level; - } - - while(current) - { - int next_offset; - - if (current->next) - { - next_offset = (int)(current->cycle / cycles_per_sample); - } - else - { - next_offset = sample_buff_sz; - } - - for(f = offset; f < next_offset; f++) - { - sample[f] = current->level; - } - - offset = next_offset; - sound.last_level = current->level; - current = current->next; - } - } - - AUDIOQueue(sample, sample_buff_sz); - - free(sample); - ClearSoundRecord(); - } - } /* Draw scanline @@ -595,10 +618,14 @@ static int CheckTimers(Z80 *z80, Z80Val val) if (y>=0 && y> AUDIO_SCALE; + + audio_sample_sz = + (int)((double)freq / + (double)IConfig(CONF_FRAMES_PER_SEC) * + (double)AUDIO_FRAMES); + + return freq; +} + + /* END OF FILE */ diff --git a/src/spec.h b/src/spec.h index 28c89fd..412c92d 100644 --- a/src/spec.h +++ b/src/spec.h @@ -59,6 +59,10 @@ void SPECShowScreen(void); */ void SPECReset(Z80 *z80); +/* Return the audio frequency wanted by the Spectrum +*/ +int SPECAudioFrequency(void); + #endif -- cgit v1.3