From 065e37f0954109da9bad2781aacd608027e6128a Mon Sep 17 00:00:00 2001 From: Ignacio Sanchez Gines <863613+drhelius@users.noreply.github.com> Date: Fri, 5 Jan 2024 00:41:03 +0100 Subject: [PATCH] Add support for SGM AY8910 sound chip. Fix #11 --- platforms/desktop-shared/Makefile.common | 2 +- platforms/desktop-shared/emu.cpp | 4 +- platforms/libretro/Makefile.common | 1 + platforms/windows/Gearcoleco.vcxproj | 2 + src/AY8910.cpp | 400 +++++++++++++++++++++++ src/AY8910.h | 73 +++++ src/Audio.cpp | 19 +- src/Audio.h | 17 +- src/definitions.h | 1 + 9 files changed, 504 insertions(+), 15 deletions(-) create mode 100644 src/AY8910.cpp create mode 100644 src/AY8910.h diff --git a/platforms/desktop-shared/Makefile.common b/platforms/desktop-shared/Makefile.common index 26a7da4..3f01197 100644 --- a/platforms/desktop-shared/Makefile.common +++ b/platforms/desktop-shared/Makefile.common @@ -17,7 +17,7 @@ SOURCES = $(EMULATOR_DESKTOP_SHARED_SRC)/main.cpp $(EMULATOR_DESKTOP_SHARED_SRC) SOURCES += $(IMGUI_SRC)/imgui_impl_sdl.cpp $(IMGUI_SRC)/imgui_impl_opengl2.cpp $(IMGUI_SRC)/imgui.cpp $(IMGUI_SRC)/imgui_demo.cpp $(IMGUI_SRC)/imgui_draw.cpp $(IMGUI_SRC)/imgui_widgets.cpp $(IMGUI_FILEBROWSER_SRC)/ImGuiFileBrowser.cpp -SOURCES += $(EMULATOR_SRC)/Audio.cpp $(EMULATOR_SRC)/Cartridge.cpp $(EMULATOR_SRC)/GearcolecoCore.cpp $(EMULATOR_SRC)/Input.cpp $(EMULATOR_SRC)/Memory.cpp $(EMULATOR_SRC)/opcodes.cpp $(EMULATOR_SRC)/opcodes_cb.cpp $(EMULATOR_SRC)/opcodes_ed.cpp $(EMULATOR_SRC)/Processor.cpp $(EMULATOR_SRC)/ColecoVisionIOPorts.cpp $(EMULATOR_SRC)/Video.cpp +SOURCES += $(EMULATOR_SRC)/Audio.cpp $(EMULATOR_SRC)/Cartridge.cpp $(EMULATOR_SRC)/GearcolecoCore.cpp $(EMULATOR_SRC)/Input.cpp $(EMULATOR_SRC)/Memory.cpp $(EMULATOR_SRC)/opcodes.cpp $(EMULATOR_SRC)/opcodes_cb.cpp $(EMULATOR_SRC)/opcodes_ed.cpp $(EMULATOR_SRC)/Processor.cpp $(EMULATOR_SRC)/ColecoVisionIOPorts.cpp $(EMULATOR_SRC)/Video.cpp $(EMULATOR_SRC)/AY8910.cpp SOURCES += $(EMULATOR_AUDIO_SRC)/Blip_Buffer.cpp $(EMULATOR_AUDIO_SRC)/Effects_Buffer.cpp $(EMULATOR_AUDIO_SRC)/Sms_Apu.cpp $(EMULATOR_AUDIO_SRC)/Multi_Buffer.cpp diff --git a/platforms/desktop-shared/emu.cpp b/platforms/desktop-shared/emu.cpp index 9ae2393..935f7fe 100644 --- a/platforms/desktop-shared/emu.cpp +++ b/platforms/desktop-shared/emu.cpp @@ -67,7 +67,7 @@ void emu_init(void) gearcoleco->Init(); sound_queue = new Sound_Queue(); - sound_queue->start(44100, 2); + sound_queue->start(GC_AUDIO_SAMPLE_RATE, 2); audio_buffer = new s16[GC_AUDIO_BUFFER_SIZE]; @@ -198,7 +198,7 @@ void emu_audio_volume(float volume) void emu_audio_reset(void) { sound_queue->stop(); - sound_queue->start(44100, 2); + sound_queue->start(GC_AUDIO_SAMPLE_RATE, 2); } bool emu_is_audio_enabled(void) diff --git a/platforms/libretro/Makefile.common b/platforms/libretro/Makefile.common index 77e21ce..b84f1c7 100644 --- a/platforms/libretro/Makefile.common +++ b/platforms/libretro/Makefile.common @@ -5,6 +5,7 @@ SOURCES_CXX := $(CORE_DIR)/libretro.cpp \ $(SOURCE_DIR)/Processor.cpp \ $(SOURCE_DIR)/Video.cpp \ $(SOURCE_DIR)/Audio.cpp \ + $(SOURCE_DIR)/AY8910.cpp \ $(SOURCE_DIR)/Input.cpp \ $(SOURCE_DIR)/Cartridge.cpp \ $(SOURCE_DIR)/ColecoVisionIOPorts.cpp \ diff --git a/platforms/windows/Gearcoleco.vcxproj b/platforms/windows/Gearcoleco.vcxproj index c6ca9bb..6a7ded9 100644 --- a/platforms/windows/Gearcoleco.vcxproj +++ b/platforms/windows/Gearcoleco.vcxproj @@ -12,6 +12,7 @@ + @@ -44,6 +45,7 @@ + diff --git a/src/AY8910.cpp b/src/AY8910.cpp new file mode 100644 index 0000000..1a4c647 --- /dev/null +++ b/src/AY8910.cpp @@ -0,0 +1,400 @@ +/* + * Gearcoleco - ColecoVision Emulator + * Copyright (C) 2021 Ignacio Sanchez + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ + * + */ + +#include "AY8910.h" + +AY8910::AY8910() +{ + InitPointer(m_pBuffer); +} + +AY8910::~AY8910() +{ + SafeDelete(m_pBuffer); +} + +void AY8910::Init(int clockRate) +{ + m_pBuffer = new s16[GC_AUDIO_BUFFER_SIZE]; + Reset(clockRate); +} + +void AY8910::Reset(int clockRate) +{ + m_iClockRate = clockRate; + + for (int i = 0; i < 16; i++) + { + m_Registers[i] = 0; + } + + for (int i = 0; i < 3; i++) + { + m_TonePeriod[i] = 0; + m_ToneCounter[i] = 0; + m_Amplitude[i] = 0; + m_ToneDisable[i] = false; + m_NoiseDisable[i] = false; + m_EnvelopeMode[i] = false; + m_Sign[i] = false; + } + + m_SelectedRegister = 0; + m_NoisePeriod = 0; + m_NoiseCounter = 0; + m_NoiseShift = 1; + m_EnvelopePeriod = 0; + m_EnvelopeCounter = 0; + m_EnvelopeSegment = false; + m_EnvelopeStep = 0; + m_EnvelopeVolume = 0; + m_iCycleCounter = 0; + m_iSampleCounter = 0; + m_iBufferIndex = 0; + + for (int i = 0; i < GC_AUDIO_BUFFER_SIZE; i++) + { + m_pBuffer[i] = 0; + } + + m_ElapsedCycles = 0; +} + +void AY8910::WriteRegister(u8 value) +{ + Sync(); + + m_Registers[m_SelectedRegister] = value & kAY8910RegisterMask[m_SelectedRegister]; + + switch (m_SelectedRegister) + { + // Channel A tone period + case 0: + case 1: + { + m_TonePeriod[0] = (m_Registers[1] << 8) | m_Registers[0]; + if (m_TonePeriod[0] == 0) + { + m_TonePeriod[0] = 1; + } + break; + } + // Channel B tone period + case 2: + case 3: + { + m_TonePeriod[1] = (m_Registers[3] << 8) | m_Registers[2]; + if (m_TonePeriod[1] == 0) + { + m_TonePeriod[1] = 1; + } + break; + } + // Channel C tone period + case 4: + case 5: + { + m_TonePeriod[2] = (m_Registers[5] << 8) | m_Registers[4]; + if (m_TonePeriod[2] == 0) + { + m_TonePeriod[2] = 1; + } + break; + } + // Noise period + case 6: + { + m_NoisePeriod = m_Registers[6]; + if (m_NoisePeriod == 0) + { + m_NoisePeriod = 1; + } + break; + } + // Mixer + case 7: + { + m_ToneDisable[0] = IsSetBit(m_Registers[7], 0); + m_ToneDisable[1] = IsSetBit(m_Registers[7], 1); + m_ToneDisable[2] = IsSetBit(m_Registers[7], 2); + m_NoiseDisable[0] = IsSetBit(m_Registers[7], 3); + m_NoiseDisable[1] = IsSetBit(m_Registers[7], 4); + m_NoiseDisable[2] = IsSetBit(m_Registers[7], 5); + break; + } + // Channel A amplitude + case 8: + { + m_Amplitude[0] = m_Registers[8] & 0x0F; + m_EnvelopeMode[0] = IsSetBit(m_Registers[8], 4); + break; + } + // Channel B amplitude + case 9: + { + m_Amplitude[1] = m_Registers[9] & 0x0F; + m_EnvelopeMode[1] = IsSetBit(m_Registers[9], 4); + break; + } + // Channel C amplitude + case 10: + { + m_Amplitude[2] = m_Registers[10] & 0x0F; + m_EnvelopeMode[2] = IsSetBit(m_Registers[10], 4); + break; + } + // Envelope period + case 11: + case 12: + { + m_EnvelopePeriod = (m_Registers[12] << 8) | m_Registers[11]; + break; + } + // Envelope shape + case 13: + { + m_EnvelopeCounter = 0; + m_EnvelopeSegment = false; + EnvelopeReset(); + break; + } + default: + { + break; + } + } +} + +u8 AY8910::ReadRegister() +{ + return m_Registers[m_SelectedRegister]; +} + +void AY8910::SelectRegister(u8 reg) +{ + m_SelectedRegister = reg & 0x0F; +} + +void AY8910::EnvelopeReset() +{ + m_EnvelopeStep = 0; + + if (m_EnvelopeSegment) + { + switch (m_Registers[13]) + { + case 8: + case 11: + case 13: + case 14: + { + m_EnvelopeVolume = 0x0F; + break; + } + default: + { + m_EnvelopeVolume = 0x00; + break; + } + } + } + else + { + m_EnvelopeVolume = IsSetBit(m_Registers[13], 2) ? 0x00 : 0x0F; + } +} + +void AY8910::Tick(unsigned int clockCycles) +{ + m_ElapsedCycles += clockCycles; +} + +void AY8910::Sync() +{ + for (int i = 0; i < m_ElapsedCycles; i++) + { + m_iCycleCounter ++; + if (m_iCycleCounter >= 16) + { + m_iCycleCounter -= 16; + + for (int i = 0; i < 3; i++) + { + m_ToneCounter[i]++; + if (m_ToneCounter[i] >= m_TonePeriod[i]) + { + m_ToneCounter[i] = 0; + m_Sign[i] = !m_Sign[i]; + } + } + + m_NoiseCounter++; + if (m_NoiseCounter >= (m_NoisePeriod << 1)) + { + m_NoiseCounter = 0; + m_NoiseShift = (m_NoiseShift >> 1) | (((m_NoiseShift ^ (m_NoiseShift >> 3)) & 0x01) << 16); + } + + m_EnvelopeCounter++; + if (m_EnvelopeCounter >= (m_EnvelopePeriod << 1)) + { + m_EnvelopeCounter = 0; + + if (m_EnvelopeStep) + { + if (m_EnvelopeSegment) + { + if ((m_Registers[13] == 10) || (m_Registers[13] == 12)) + { + m_EnvelopeVolume++; + } + else if ((m_Registers[13] == 8) || (m_Registers[13] == 14)) + { + m_EnvelopeVolume--; + } + } + else + { + if (IsSetBit(m_Registers[13], 2)) + { + m_EnvelopeVolume++; + } + else + { + m_EnvelopeVolume--; + } + } + } + + m_EnvelopeStep++; + if (m_EnvelopeStep >= 16) + { + if ((m_Registers[13] & 0x09) == 0x08) + { + m_EnvelopeSegment = !m_EnvelopeSegment; + } + else + { + m_EnvelopeSegment = true; + } + EnvelopeReset(); + } + } + } + + m_iSampleCounter++; + int cyclesPerSample = m_iClockRate / GC_AUDIO_SAMPLE_RATE; + if (m_iSampleCounter >= cyclesPerSample) + { + m_iSampleCounter -= cyclesPerSample; + s16 sample = 0; + + for (int i = 0; i < 3; i++) + { + if ((m_ToneDisable[i] || m_Sign[i]) && (m_NoiseDisable[i] || ((m_NoiseShift & 0x01) == 0x01))) + { + sample += m_EnvelopeMode[i] ? kAY8910VolumeTable[m_EnvelopeVolume] : kAY8910VolumeTable[m_Amplitude[i]]; + } + } + + m_pBuffer[m_iBufferIndex] = sample; + m_pBuffer[m_iBufferIndex + 1] = sample; + m_iBufferIndex += 2; + + if (m_iBufferIndex >= GC_AUDIO_BUFFER_SIZE) + { + Log("SGM Audio buffer overflow"); + m_iBufferIndex = 0; + } + } + } + + m_ElapsedCycles = 0; +} + +int AY8910::EndFrame(s16* pSampleBuffer) +{ + Sync(); + + int ret = 0; + + if (IsValidPointer(pSampleBuffer)) + { + ret = m_iBufferIndex; + + for (int i = 0; i < m_iBufferIndex; i++) + { + pSampleBuffer[i] = m_pBuffer[i]; + } + } + + m_iBufferIndex = 0; + + return ret; +} + +void AY8910::SaveState(std::ostream& stream) +{ + stream.write(reinterpret_cast(m_Registers), sizeof(m_Registers)); + stream.write(reinterpret_cast(&m_SelectedRegister), sizeof(m_SelectedRegister)); + stream.write(reinterpret_cast(m_TonePeriod), sizeof(m_TonePeriod)); + stream.write(reinterpret_cast(m_ToneCounter), sizeof(m_ToneCounter)); + stream.write(reinterpret_cast(m_Amplitude), sizeof(m_Amplitude)); + stream.write(reinterpret_cast(&m_NoisePeriod), sizeof(m_NoisePeriod)); + stream.write(reinterpret_cast(&m_NoiseCounter), sizeof(m_NoiseCounter)); + stream.write(reinterpret_cast(&m_NoiseShift), sizeof(m_NoiseShift)); + stream.write(reinterpret_cast(&m_EnvelopePeriod), sizeof(m_EnvelopePeriod)); + stream.write(reinterpret_cast(&m_EnvelopeCounter), sizeof(m_EnvelopeCounter)); + stream.write(reinterpret_cast(&m_EnvelopeSegment), sizeof(m_EnvelopeSegment)); + stream.write(reinterpret_cast(&m_EnvelopeStep), sizeof(m_EnvelopeStep)); + stream.write(reinterpret_cast(&m_EnvelopeVolume), sizeof(m_EnvelopeVolume)); + stream.write(reinterpret_cast(m_ToneDisable), sizeof(m_ToneDisable)); + stream.write(reinterpret_cast(m_NoiseDisable), sizeof(m_NoiseDisable)); + stream.write(reinterpret_cast(m_EnvelopeMode), sizeof(m_EnvelopeMode)); + stream.write(reinterpret_cast(m_Sign), sizeof(m_Sign)); + stream.write(reinterpret_cast(&m_iCycleCounter), sizeof(m_iCycleCounter)); + stream.write(reinterpret_cast(&m_iSampleCounter), sizeof(m_iSampleCounter)); + stream.write(reinterpret_cast(m_pBuffer), GC_AUDIO_BUFFER_SIZE * sizeof(s16)); + stream.write(reinterpret_cast(&m_iBufferIndex), sizeof(m_iBufferIndex)); +} + +void AY8910::LoadState(std::istream& stream) +{ + stream.read(reinterpret_cast(m_Registers), sizeof(m_Registers)); + stream.read(reinterpret_cast(&m_SelectedRegister), sizeof(m_SelectedRegister)); + stream.read(reinterpret_cast(m_TonePeriod), sizeof(m_TonePeriod)); + stream.read(reinterpret_cast(m_ToneCounter), sizeof(m_ToneCounter)); + stream.read(reinterpret_cast(m_Amplitude), sizeof(m_Amplitude)); + stream.read(reinterpret_cast(&m_NoisePeriod), sizeof(m_NoisePeriod)); + stream.read(reinterpret_cast(&m_NoiseCounter), sizeof(m_NoiseCounter)); + stream.read(reinterpret_cast(&m_NoiseShift), sizeof(m_NoiseShift)); + stream.read(reinterpret_cast(&m_EnvelopePeriod), sizeof(m_EnvelopePeriod)); + stream.read(reinterpret_cast(&m_EnvelopeCounter), sizeof(m_EnvelopeCounter)); + stream.read(reinterpret_cast(&m_EnvelopeSegment), sizeof(m_EnvelopeSegment)); + stream.read(reinterpret_cast(&m_EnvelopeStep), sizeof(m_EnvelopeStep)); + stream.read(reinterpret_cast(&m_EnvelopeVolume), sizeof(m_EnvelopeVolume)); + stream.read(reinterpret_cast(m_ToneDisable), sizeof(m_ToneDisable)); + stream.read(reinterpret_cast(m_NoiseDisable), sizeof(m_NoiseDisable)); + stream.read(reinterpret_cast(m_EnvelopeMode), sizeof(m_EnvelopeMode)); + stream.read(reinterpret_cast(m_Sign), sizeof(m_Sign)); + stream.read(reinterpret_cast(&m_iCycleCounter), sizeof(m_iCycleCounter)); + stream.read(reinterpret_cast(&m_iSampleCounter), sizeof(m_iSampleCounter)); + stream.read(reinterpret_cast(m_pBuffer), GC_AUDIO_BUFFER_SIZE * sizeof(s16)); + stream.read(reinterpret_cast(&m_iBufferIndex), sizeof(m_iBufferIndex)); +} \ No newline at end of file diff --git a/src/AY8910.h b/src/AY8910.h new file mode 100644 index 0000000..81cf1e4 --- /dev/null +++ b/src/AY8910.h @@ -0,0 +1,73 @@ +/* + * Gearcoleco - ColecoVision Emulator + * Copyright (C) 2021 Ignacio Sanchez + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ + * + */ + +#ifndef AY8910_H +#define AY8910_H + +#include "definitions.h" + +class AY8910 +{ +public: + AY8910(); + ~AY8910(); + void Init(int clockRate); + void Reset(int clockRate); + void WriteRegister(u8 value); + u8 ReadRegister(); + void SelectRegister(u8 reg); + void Tick(unsigned int clockCycles); + int EndFrame(s16* pSampleBuffer); + void SaveState(std::ostream& stream); + void LoadState(std::istream& stream); + +private: + void EnvelopeReset(); + void Sync(); + +private: + u8 m_Registers[16]; + u8 m_SelectedRegister; + u16 m_TonePeriod[3]; + u16 m_ToneCounter[3]; + u8 m_Amplitude[3]; + u8 m_NoisePeriod; + u16 m_NoiseCounter; + u32 m_NoiseShift; + u16 m_EnvelopePeriod; + u16 m_EnvelopeCounter; + bool m_EnvelopeSegment; + u8 m_EnvelopeStep; + u8 m_EnvelopeVolume; + bool m_ToneDisable[3]; + bool m_NoiseDisable[3]; + bool m_EnvelopeMode[3]; + bool m_Sign[3]; + int m_iCycleCounter; + int m_iSampleCounter; + s16* m_pBuffer; + int m_iBufferIndex; + int m_ElapsedCycles; + int m_iClockRate; +}; + +const u8 kAY8910RegisterMask[16] = {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x1F, 0xFF, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF}; +const s16 kAY8910VolumeTable[16] = {0, 40, 60, 86, 124, 186, 264, 440, 518, 840, 1196, 1526, 2016, 2602, 3300, 4096}; + +#endif /* AY8910_H */ \ No newline at end of file diff --git a/src/Audio.cpp b/src/Audio.cpp index eb95f86..1cd82a4 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -22,11 +22,13 @@ Audio::Audio() { m_ElapsedCycles = 0; - m_iSampleRate = 44100; + m_iSampleRate = GC_AUDIO_SAMPLE_RATE; InitPointer(m_pApu); InitPointer(m_pBuffer); InitPointer(m_pSampleBuffer); m_bPAL = false; + InitPointer(m_pAY8910); + InitPointer(m_pSGMBuffer); } Audio::~Audio() @@ -34,6 +36,8 @@ Audio::~Audio() SafeDelete(m_pApu); SafeDelete(m_pBuffer); SafeDeleteArray(m_pSampleBuffer); + SafeDelete(m_pAY8910); + SafeDeleteArray(m_pSGMBuffer); } void Audio::Init() @@ -50,6 +54,11 @@ void Audio::Init() //m_pBuffer->bass_freq(100); m_pApu->output(m_pBuffer->center(), m_pBuffer->left(), m_pBuffer->right()); + + m_pSGMBuffer = new s16[GC_AUDIO_BUFFER_SIZE]; + + m_pAY8910 = new AY8910(); + m_pAY8910->Init(m_bPAL ? GC_MASTER_CLOCK_PAL : GC_MASTER_CLOCK_NTSC); } void Audio::Reset(bool bPAL) @@ -59,6 +68,7 @@ void Audio::Reset(bool bPAL) m_pBuffer->clear(); m_pBuffer->clock_rate(m_bPAL ? GC_MASTER_CLOCK_PAL : GC_MASTER_CLOCK_NTSC); m_ElapsedCycles = 0; + m_pAY8910->Reset(m_bPAL ? GC_MASTER_CLOCK_PAL : GC_MASTER_CLOCK_NTSC); } void Audio::SetSampleRate(int rate) @@ -82,13 +92,15 @@ void Audio::EndFrame(s16* pSampleBuffer, int* pSampleCount) int count = static_cast(m_pBuffer->read_samples(m_pSampleBuffer, GC_AUDIO_BUFFER_SIZE)); + m_pAY8910->EndFrame(m_pSGMBuffer); + if (IsValidPointer(pSampleBuffer) && IsValidPointer(pSampleCount)) { *pSampleCount = count; for (int i=0; i (&m_ElapsedCycles), sizeof(m_ElapsedCycles)); stream.write(reinterpret_cast (m_pSampleBuffer), sizeof(blip_sample_t) * GC_AUDIO_BUFFER_SIZE); - + m_pAY8910->SaveState(stream); } void Audio::LoadState(std::istream& stream) { stream.read(reinterpret_cast (&m_ElapsedCycles), sizeof(m_ElapsedCycles)); stream.read(reinterpret_cast (m_pSampleBuffer), sizeof(blip_sample_t) * GC_AUDIO_BUFFER_SIZE); + m_pAY8910->LoadState(stream); m_pApu->reset(); m_pBuffer->clear(); diff --git a/src/Audio.h b/src/Audio.h index 0a4be27..2a124cf 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -23,6 +23,7 @@ #include "definitions.h" #include "audio/Multi_Buffer.h" #include "audio/Sms_Apu.h" +#include "AY8910.h" class Audio { @@ -45,17 +46,20 @@ class Audio private: Sms_Apu* m_pApu; Stereo_Buffer* m_pBuffer; - int m_ElapsedCycles; + AY8910* m_pAY8910; + u64 m_ElapsedCycles; int m_iSampleRate; blip_sample_t* m_pSampleBuffer; bool m_bPAL; u8 m_SGMRegister; u8 m_SGMRegisters[16]; + s16* m_pSGMBuffer; }; inline void Audio::Tick(unsigned int clockCycles) { m_ElapsedCycles += clockCycles; + m_pAY8910->Tick(clockCycles); } inline void Audio::WriteAudioRegister(u8 value) @@ -65,22 +69,17 @@ inline void Audio::WriteAudioRegister(u8 value) inline void Audio::SGMWrite(u8 value) { - uint8_t mask[16] = { - 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x1F, 0xFF, - 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, - }; - - m_SGMRegisters[m_SGMRegister] = value & mask[m_SGMRegister]; + m_pAY8910->WriteRegister(value); } inline u8 Audio::SGMRead() { - return m_SGMRegisters[m_SGMRegister]; + return m_pAY8910->ReadRegister(); } inline void Audio::SGMRegister(u8 reg) { - m_SGMRegister = reg & 0x0F; + m_pAY8910->SelectRegister(reg); } #endif /* AUDIO_H */ diff --git a/src/definitions.h b/src/definitions.h index 7a1e1a9..bf48e68 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -102,6 +102,7 @@ typedef void (*RamChangedCallback) (void); #define GC_LINES_PER_FRAME_PAL 313 #define GC_FRAMES_PER_SECOND_PAL 50 +#define GC_AUDIO_SAMPLE_RATE 44100 #define GC_AUDIO_BUFFER_SIZE 8192 #define GC_SAVESTATE_MAGIC 0x09200902