diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio.c | 6 | ||||
| -rw-r--r-- | src/audio.h | 10 | ||||
| -rw-r--r-- | src/main.c | 2 | ||||
| -rw-r--r-- | src/spec.c | 168 | ||||
| -rw-r--r-- | 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 <stdlib.h> #include <SDL.h> -/* 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 @@ -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"); } @@ -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; + + sample = Malloc(audio_sample_sz); -static int CheckTimers(Z80 *z80, Z80Val val) + 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<GFX_HEIGHT && enable_screen) DrawScanline(y); - - Z80SetTimer(z80, eZ80_Timer_1, 0); } +} + +static int CheckTimers(Z80 *z80, Z80Val val) +{ + CheckSound(z80); + CheckScanlines(z80); return TRUE; } @@ -634,14 +661,6 @@ void SPECInit(Z80 *z80) Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); - /* Calculate the audio buffer sizes - */ - if (IConfig(CONF_SOUND)) - { - sample_buff_sz = SAMPLE_RATE / IConfig(CONF_FRAMES_PER_SEC); - cycles_per_sample = (double)FRAME_CYCLES / (double)SAMPLE_RATE; - } - SPECReset(z80); } @@ -732,7 +751,7 @@ void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val) { case 0xfe: /* ULA */ border=val&0x07; - AddSoundRecord(Z80GetTimer(z80, eZ80_Timer_1), val & 0x10 ? 64 : 0); + AddSoundRecord(Z80GetTimer(z80, AUDIO_TIMER), val & 0x10 ? 64 : 0); break; case 0xfb: /* TODO: ZX Printer */ @@ -1012,4 +1031,17 @@ void SPECReset(Z80 *z80) } +int SPECAudioFrequency(void) +{ + int freq = FRAME_CYCLES * IConfig(CONF_FRAMES_PER_SEC) >> AUDIO_SCALE; + + audio_sample_sz = + (int)((double)freq / + (double)IConfig(CONF_FRAMES_PER_SEC) * + (double)AUDIO_FRAMES); + + return freq; +} + + /* END OF FILE */ @@ -59,6 +59,10 @@ void SPECShowScreen(void); */ void SPECReset(Z80 *z80); +/* Return the audio frequency wanted by the Spectrum +*/ +int SPECAudioFrequency(void); + #endif |
