summaryrefslogtreecommitdiff
path: root/src/spec.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2026-06-29 09:41:42 +0900
committerIan C <ianc@noddybox.co.uk>2026-06-29 09:41:42 +0900
commitc527acfc79f3bda8cfe13a7b51b0b16a32683960 (patch)
treee5bbd119a070848301a03b52f1232a797b35c119 /src/spec.c
parentc31b779c20638ce25f11489c445a53798a663b13 (diff)
First partial working attempt at sound. Producing output, but very distorted
Diffstat (limited to 'src/spec.c')
-rw-r--r--src/spec.c115
1 files changed, 113 insertions, 2 deletions
diff --git a/src/spec.c b/src/spec.c
index 2ddf661..6393ef2 100644
--- a/src/spec.c
+++ b/src/spec.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <SDL.h>
#include "spec.h"
#include "snap.h"
#include "gfx.h"
@@ -33,6 +34,7 @@
#include "config.h"
#include "exit.h"
#include "tape.h"
+#include "audio.h"
#include "util.h"
#ifndef TRUE
@@ -77,7 +79,9 @@ static Z80Byte mem[0x10000];
/* Number of cycles per scan lines and scan line control
*/
-static Z80Val SCAN_CYCLES=224;
+#define SCAN_CYCLES 224
+#define FRAME_CYCLES 69888
+
static int scanline=0;
static int enable_screen=TRUE;
@@ -202,6 +206,22 @@ static const MatrixMap keymap[]=
{SDLK_UNKNOWN, 0,0,0,0},
};
+static size_t sample_buff_sz;
+static double cycles_per_sample;
+
+typedef struct SoundRecord
+{
+ Z80Val cycle;
+ Uint8 level;
+ struct SoundRecord *next;
+} SoundRecord;
+
+static struct
+{
+ SoundRecord *head;
+ SoundRecord *tail;
+ Uint8 last_level;
+} sound;
/* ---------------------------------------- DEBUG FUNCTIONS
*/
@@ -251,6 +271,39 @@ static void ClearKeys(void)
}
}
+static void AddSoundRecord(Z80Val cycle, Uint8 level)
+{
+ SoundRecord *new = Malloc(sizeof *new);
+
+ new->cycle = cycle;
+ new->level = level;
+ new->next = NULL;
+
+ if (sound.tail)
+ {
+ sound.tail->next = new;
+ sound.tail = new;
+ }
+ else
+ {
+ sound.head = new;
+ sound.tail = new;
+ }
+}
+
+static void ClearSoundRecord(void)
+{
+ while(sound.head)
+ {
+ SoundRecord *next = sound.head->next;
+ free(sound.head);
+ sound.head = next;
+ }
+
+ sound.tail = NULL;
+}
+
+
static void DrawScanlineAt(int y, int sline)
{
int aline;
@@ -485,6 +538,55 @@ 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
@@ -494,7 +596,7 @@ static int CheckTimers(Z80 *z80, Z80Val val)
if (y>=0 && y<GFX_HEIGHT && enable_screen)
DrawScanline(y);
- /* TODO: Process sound emulation */
+ Z80SetTimer(z80, eZ80_Timer_1, 0);
}
return TRUE;
@@ -532,6 +634,14 @@ 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);
}
@@ -622,6 +732,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);
break;
case 0xfb: /* TODO: ZX Printer */