From f18eb2fef2ff7e2ba827bbf38acf4f463c027f19 Mon Sep 17 00:00:00 2001 From: goyuken Date: Sun, 9 Sep 2012 00:41:11 +0000 Subject: [PATCH] gambatte now has sound! output from the core is original 2MEGAHURTZ audio, but libspeexdsp handles it fine. seems to be a lot of DC offset at times; not sure if there's a good way to remove it --- .../Consoles/Gambatte/Gambatte.cs | 58 +++++++++++++++++-- .../Sound/Utilities/SpeexResampler.cs | 24 +++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Gambatte/Gambatte.cs b/BizHawk.Emulation/Consoles/Gambatte/Gambatte.cs index 36acc9b532..8fba46ba58 100644 --- a/BizHawk.Emulation/Consoles/Gambatte/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Gambatte/Gambatte.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Consoles.Gambatte /// /// a gameboy/gameboy color emulator wrapped around native C++ libgambatte /// - public class Gambatte : IEmulator, IVideoProvider + public class Gambatte : IEmulator, IVideoProvider, ISoundProvider { /// /// internal gambatte state @@ -34,6 +34,8 @@ namespace BizHawk.Emulation.Consoles.Gambatte if (LibGambatte.gambatte_load(GambatteState, "gambattetmp.gb", 0) != 0) throw new Exception("gambatte_load() returned non-zero (is this not a gb or gbc rom?)"); + + InitSound(); } public IVideoProvider VideoProvider @@ -43,7 +45,7 @@ namespace BizHawk.Emulation.Consoles.Gambatte public ISoundProvider SoundProvider { - get { return new NullSound(); } + get { return this; } } @@ -65,13 +67,15 @@ namespace BizHawk.Emulation.Consoles.Gambatte public IController Controller { get; set; } - short[] soundscratch = new short[(35112 + 2064) * 2]; + uint[] videoscratch = new uint[160 * 144]; public void FrameAdvance(bool render) { uint nsamp = 35112; - LibGambatte.gambatte_runfor(GambatteState, videoscratch, 160, soundscratch, ref nsamp); + LibGambatte.gambatte_runfor(GambatteState, videoscratch, 160, soundbuff, ref nsamp); + + soundbuffcontains = (int)nsamp; // can't convert uint[] to int[], so we do this instead // TODO: lie in the p/invoke layer and claim unsigned* is really int* @@ -144,8 +148,8 @@ namespace BizHawk.Emulation.Consoles.Gambatte CoreOutputComm GbOutputComm = new CoreOutputComm { - VsyncNum = 60, - VsyncDen = 1, + VsyncNum = 262144, + VsyncDen = 4389, RomStatusAnnotation = "Bizwhackin it up", RomStatusDetails = "LEVAR BURTON" }; @@ -205,5 +209,47 @@ namespace BizHawk.Emulation.Consoles.Gambatte } #endregion + + #region ISoundProvider + + /// + /// sample pairs before resampling + /// + short[] soundbuff = new short[(35112 + 2064) * 2]; + /// + /// how many sample pairs are in soundbuff + /// + int soundbuffcontains = 0; + + Sound.Utilities.SpeexResampler resampler; + Sound.MetaspuSoundProvider metaspu; + + void InitSound() + { + metaspu = new Sound.MetaspuSoundProvider(Sound.ESynchMethod.ESynchMethod_V); + resampler = new Sound.Utilities.SpeexResampler(5, 2097152, 44100, 2097152, 44100, metaspu.buffer.enqueue_samples); + } + + public void GetSamples(short[] samples) + { + resampler.EnqueueSamples(soundbuff, soundbuffcontains); + //for (int i = 0; soundbuffcontains >= 0; soundbuffcontains--) + //{ + // resampler.EnqueueSample(soundbuff[i], soundbuff[i + 1]); + // i += 2; + //} + + soundbuffcontains = 0; + resampler.Flush(); + metaspu.GetSamples(samples); + } + + public void DiscardSamples() + { + metaspu.DiscardSamples(); + } + + public int MaxVolume { get; set; } + #endregion } } diff --git a/BizHawk.Emulation/Sound/Utilities/SpeexResampler.cs b/BizHawk.Emulation/Sound/Utilities/SpeexResampler.cs index e442c43c3d..dd12073d6b 100644 --- a/BizHawk.Emulation/Sound/Utilities/SpeexResampler.cs +++ b/BizHawk.Emulation/Sound/Utilities/SpeexResampler.cs @@ -264,7 +264,8 @@ namespace BizHawk.Emulation.Sound.Utilities /// Action drainer; - short[] inbuf = new short[512]; + // TODO: this size is roughly based on how big you can make the buffer before the snes resampling (32040.5 -> 44100) gets screwed up + short[] inbuf = new short[512]; //[8192]; // [512]; short[] outbuf; @@ -336,6 +337,27 @@ namespace BizHawk.Emulation.Sound.Utilities Flush(); } + /// + /// add multiple samples to the queue + /// + /// interleaved stereo samples + /// number of sample pairs + public void EnqueueSamples(short[] userbuf, int nsamp) + { + int numused = 0; + while (numused < nsamp) + { + int shortstocopy = Math.Min(inbuf.Length - inbufpos, (nsamp - numused) * 2); + + Buffer.BlockCopy(userbuf, numused * 2 * sizeof(short), inbuf, inbufpos * sizeof(short), shortstocopy * sizeof(short)); + inbufpos += shortstocopy; + numused += shortstocopy / 2; + + if (inbufpos == inbuf.Length) + Flush(); + } + } + /// /// flush as many input samples as possible, generating output samples right now