diff --git a/BizHawk.Client.Common/RomGame.cs b/BizHawk.Client.Common/RomGame.cs index 9badb6d7da..f225c96458 100644 --- a/BizHawk.Client.Common/RomGame.cs +++ b/BizHawk.Client.Common/RomGame.cs @@ -66,7 +66,8 @@ namespace BizHawk.Client.Common { RomData = FileData; } - else if (file.Extension == ".DSK" || file.Extension == ".TAP" || file.Extension == ".TZX" || file.Extension == ".PZX" || file.Extension == ".CSW") + else if (file.Extension == ".DSK" || file.Extension == ".TAP" || file.Extension == ".TZX" || + file.Extension == ".PZX" || file.Extension == ".CSW" || file.Extension == ".WAV") { // these are not roms. unforunately if treated as such there are certain edge-cases // where a header offset is detected. This should mitigate this issue until a cleaner solution is found diff --git a/BizHawk.Client.EmuHawk/FileLoader.cs b/BizHawk.Client.EmuHawk/FileLoader.cs index da87ee0402..befabbc9c4 100644 --- a/BizHawk.Client.EmuHawk/FileLoader.cs +++ b/BizHawk.Client.EmuHawk/FileLoader.cs @@ -51,7 +51,7 @@ namespace BizHawk.Client.EmuHawk return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", - ".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX", ".PZX", ".CSW" + ".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX", ".PZX", ".CSW", ".WAV" }; } diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index b44096f7cc..e7064c304c 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2081,7 +2081,7 @@ namespace BizHawk.Client.EmuHawk if (VersionInfo.DeveloperBuild) { return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;*.tzx;*.pzx;*.csw;%ARCH%", + "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;*.tzx;*.pzx;*.csw;*.wav;%ARCH%", "Music Files", "*.psf;*.minipsf;*.sid;*.nsf", "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", @@ -2109,7 +2109,7 @@ namespace BizHawk.Client.EmuHawk "Apple II", "*.dsk;*.do;*.po;%ARCH%", "Virtual Boy", "*.vb;%ARCH%", "Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%", - "Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;*.pzx;*.csw;%ARCH%", + "Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;*.pzx;*.csw;*.wav;%ARCH%", "All Files", "*.*"); } diff --git a/BizHawk.Emulation.Common/Database/Database.cs b/BizHawk.Emulation.Common/Database/Database.cs index 6f92d4ddff..5fcf3ce89f 100644 --- a/BizHawk.Emulation.Common/Database/Database.cs +++ b/BizHawk.Emulation.Common/Database/Database.cs @@ -306,11 +306,11 @@ namespace BizHawk.Emulation.Common case ".TZX": case ".PZX": case ".CSW": + case ".WAV": game.System = "ZXSpectrum"; break; - case ".TAP": - + case ".TAP": byte[] head = romData.Take(8).ToArray(); if (System.Text.Encoding.Default.GetString(head).Contains("C64-TAPE")) game.System = "C64"; diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 13dd091df7..faf0089eb2 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -299,6 +299,10 @@ + + + + diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs index 23e09b6dba..55e4a1d14c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs @@ -325,6 +325,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum TapConverter tapSer = new TapConverter(this); PzxConverter pzxSer = new PzxConverter(this); CswConverter cswSer = new CswConverter(this); + WavConverter wavSer = new WavConverter(this); // TZX if (tzxSer.CheckType(tapeData)) @@ -386,6 +387,26 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } } + // WAV + else if (wavSer.CheckType(tapeData)) + { + // this file has a csw header - attempt serialization + try + { + wavSer.Read(tapeData); + // reset block index + CurrentDataBlockIndex = 0; + return; + } + catch (Exception ex) + { + // exception during operation + var e = ex; + throw new Exception(this.GetType().ToString() + + "\n\nTape image file has a valid WAV header, but threw an exception whilst data was being parsed.\n\n" + e.ToString()); + } + } + // Assume TAP else { @@ -838,7 +859,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { if (_tapeIsPlaying && _autoPlay) { - if (DataBlocks.Count > 1 || _dataBlocks[_currentDataBlockIndex].BlockDescription != BlockType.CSW_Recording) + if (DataBlocks.Count > 1 || + (_dataBlocks[_currentDataBlockIndex].BlockDescription != BlockType.CSW_Recording && + _dataBlocks[_currentDataBlockIndex].BlockDescription != BlockType.WAV_Recording)) { // we should only stop the tape when there are multiple blocks // if we just have one big block (maybe a CSW or WAV) then auto stopping will cock things up @@ -882,8 +905,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return; // dont autostop if there is only 1 block - if (DataBlocks.Count > 2 || _dataBlocks[_currentDataBlockIndex].BlockDescription == BlockType.CSW_Recording) + if (DataBlocks.Count == 1 || _dataBlocks[_currentDataBlockIndex].BlockDescription == BlockType.CSW_Recording || + _dataBlocks[_currentDataBlockIndex].BlockDescription == BlockType.WAV_Recording + ) + { return; + } if (diff >= timeout * 2) { diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs index d2f572af1b..50af7674b0 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs @@ -207,6 +207,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // spectrum .tzx tape file return SpectrumMediaType.Tape; } + if (hdr.ToUpper().Contains("WAVE")) + { + // spectrum .tzx tape file + return SpectrumMediaType.Tape; + } // if we get this far, assume a .tap file return SpectrumMediaType.Tape; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverterType.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverterType.cs index ed89724f30..c82133037b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverterType.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverterType.cs @@ -11,6 +11,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum TAP, PZX, CSW, + WAV, DSK } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs index de839971c6..adcc0eee97 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs @@ -242,6 +242,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // zxhawk proprietry PAUSE_BLOCK, + + WAV_Recording } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/StreamHelper.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/StreamHelper.cs new file mode 100644 index 0000000000..5c24a66b61 --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/StreamHelper.cs @@ -0,0 +1,104 @@ +using System; +using System.IO; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + /// + /// From https://archive.codeplex.com/?p=zxmak2 + /// + public static class StreamHelper + { + public static void Write(Stream stream, Int32 value) + { + byte[] data = BitConverter.GetBytes(value); + stream.Write(data, 0, data.Length); + } + + public static void Write(Stream stream, UInt32 value) + { + byte[] data = BitConverter.GetBytes(value); + stream.Write(data, 0, data.Length); + } + + public static void Write(Stream stream, Int16 value) + { + byte[] data = BitConverter.GetBytes(value); + stream.Write(data, 0, data.Length); + } + + public static void Write(Stream stream, UInt16 value) + { + byte[] data = BitConverter.GetBytes(value); + stream.Write(data, 0, data.Length); + } + + public static void Write(Stream stream, Byte value) + { + byte[] data = new byte[1]; + data[0] = value; + stream.Write(data, 0, data.Length); + } + + public static void Write(Stream stream, SByte value) + { + byte[] data = new byte[1]; + data[0] = (byte)value; + stream.Write(data, 0, data.Length); + } + + public static void Write(Stream stream, byte[] value) + { + stream.Write(value, 0, value.Length); + } + + + public static void Read(Stream stream, out Int32 value) + { + byte[] data = new byte[4]; + stream.Read(data, 0, data.Length); + //if (!BitConverter.IsLittleEndian) + // Array.Reverse(data); + value = BitConverter.ToInt32(data, 0); + } + + public static void Read(Stream stream, out UInt32 value) + { + byte[] data = new byte[4]; + stream.Read(data, 0, data.Length); + value = BitConverter.ToUInt32(data, 0); + } + + public static void Read(Stream stream, out Int16 value) + { + byte[] data = new byte[2]; + stream.Read(data, 0, data.Length); + value = BitConverter.ToInt16(data, 0); + } + + public static void Read(Stream stream, out UInt16 value) + { + byte[] data = new byte[2]; + stream.Read(data, 0, data.Length); + value = BitConverter.ToUInt16(data, 0); + } + + public static void Read(Stream stream, out Byte value) + { + byte[] data = new byte[1]; + stream.Read(data, 0, data.Length); + value = data[0]; + } + + public static void Read(Stream stream, out SByte value) + { + byte[] data = new byte[1]; + stream.Read(data, 0, data.Length); + value = (sbyte)data[0]; + } + + public static void Read(Stream stream, byte[] value) + { + stream.Read(value, 0, value.Length); + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs new file mode 100644 index 0000000000..07c8d3e300 --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + /// + /// Reponsible for WAV format conversion + /// Based heavily on code from zxmak2: https://archive.codeplex.com/?p=zxmak2 + /// + public class WavConverter : MediaConverter + { + /// + /// The type of serializer + /// + private MediaConverterType _formatType = MediaConverterType.WAV; + public override MediaConverterType FormatType + { + get + { + return _formatType; + } + } + + /// + /// Signs whether this class can be used to read the data format + /// + public override bool IsReader { get { return true; } } + + /// + /// Signs whether this class can be used to write the data format + /// + public override bool IsWriter { get { return false; } } + + /// + /// Position counter + /// + private int _position = 0; + + #region Construction + + private DatacorderDevice _datacorder; + + public WavConverter(DatacorderDevice _tapeDevice) + { + _datacorder = _tapeDevice; + } + + #endregion + + /// + /// Returns TRUE if pzx header is detected + /// + /// + public override bool CheckType(byte[] data) + { + // WAV Header + + // check whether this is a valid wav format file by looking at the identifier in the header + string ident = Encoding.ASCII.GetString(data, 8, 4); + + if (ident.ToUpper() != "WAVE") + { + // this is not a valid WAV format file + return false; + } + else + { + return true; + } + } + + /// + /// DeSerialization method + /// + /// + public override void Read(byte[] data) + { + // clear existing tape blocks + _datacorder.DataBlocks.Clear(); + + // check whether this is a valid pzx format file by looking at the identifier in the header block + string ident = Encoding.ASCII.GetString(data, 8, 4); + + if (ident.ToUpper() != "WAVE") + { + // this is not a valid TZX format file + throw new Exception(this.GetType().ToString() + + "This is not a valid WAV format file"); + } + + _position = 0; + + MemoryStream stream = new MemoryStream(); + stream.Write(data, 0, data.Length); + stream.Position = 0; + + WavStreamReader reader = new WavStreamReader(stream); + + int rate = (69888 * 50) / reader.Header.sampleRate; + int smpCounter = 0; + int state = reader.ReadNext(); + + // create the single tape block + TapeDataBlock t = new TapeDataBlock(); + t.BlockDescription = BlockType.WAV_Recording; + t.BlockID = 0; + t.DataPeriods = new List(); + + for (int i = 0; i < reader.Count; i++) + { + int sample = reader.ReadNext(); + smpCounter++; + if ((state < 0 && sample < 0) || (state >= 0 && sample >= 0)) + continue; + t.DataPeriods.Add(smpCounter * rate); + smpCounter = 0; + state = sample; + } + + // add closing period + t.DataPeriods.Add((69888 * 50) / 10); + + // add to datacorder + _datacorder.DataBlocks.Add(t); + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavHeader.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavHeader.cs new file mode 100644 index 0000000000..8a19b53ed9 --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavHeader.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + /// + /// From https://archive.codeplex.com/?p=zxmak2 + /// + public class WavHeader + { + // RIFF chunk (12 bytes) + public Int32 chunkID; // "RIFF" + public Int32 fileSize; + public Int32 riffType; // "WAVE" + + // Format chunk (24 bytes) + public Int32 fmtID; // "fmt " + public Int32 fmtSize; + public Int16 fmtCode; + public Int16 channels; + public Int32 sampleRate; + public Int32 fmtAvgBPS; + public Int16 fmtBlockAlign; + public Int16 bitDepth; + public Int16 fmtExtraSize; + + // Data chunk + public Int32 dataID; // "data" + public Int32 dataSize; // The data size should be file size - 36 bytes. + + + public void Deserialize(Stream stream) + { + StreamHelper.Read(stream, out chunkID); + StreamHelper.Read(stream, out fileSize); + StreamHelper.Read(stream, out riffType); + if (chunkID != BitConverter.ToInt32(Encoding.ASCII.GetBytes("RIFF"), 0)) + { + throw new FormatException("Invalid WAV file header"); + } + if (riffType != BitConverter.ToInt32(Encoding.ASCII.GetBytes("WAVE"), 0)) + { + throw new FormatException(string.Format( + "Not supported RIFF type: '{0}'", + Encoding.ASCII.GetString(BitConverter.GetBytes(riffType)))); + } + Int32 chunkId; + Int32 chunkSize; + while (stream.Position < stream.Length) + { + StreamHelper.Read(stream, out chunkId); + StreamHelper.Read(stream, out chunkSize); + string strChunkId = Encoding.ASCII.GetString( + BitConverter.GetBytes(chunkId)); + if (strChunkId == "fmt ") + { + read_fmt(stream, chunkId, chunkSize); + } + else if (strChunkId == "data") + { + read_data(stream, chunkId, chunkSize); + break; + } + else + { + stream.Seek(chunkSize, SeekOrigin.Current); + } + } + if (fmtID != BitConverter.ToInt32(Encoding.ASCII.GetBytes("fmt "), 0)) + { + throw new FormatException("WAV format chunk not found"); + } + if (dataID != BitConverter.ToInt32(Encoding.ASCII.GetBytes("data"), 0)) + { + throw new FormatException("WAV data chunk not found"); + } + } + + private void read_data(Stream stream, int chunkId, int chunkSize) + { + dataID = chunkId; + dataSize = chunkSize; + } + + private void read_fmt(Stream stream, int chunkId, int chunkSize) + { + fmtID = chunkId; + fmtSize = chunkSize; + StreamHelper.Read(stream, out fmtCode); + StreamHelper.Read(stream, out channels); + StreamHelper.Read(stream, out sampleRate); + StreamHelper.Read(stream, out fmtAvgBPS); + StreamHelper.Read(stream, out fmtBlockAlign); + StreamHelper.Read(stream, out bitDepth); + if (fmtSize == 18) + { + // Read any extra values + StreamHelper.Read(stream, out fmtExtraSize); + stream.Seek(fmtExtraSize, SeekOrigin.Current); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavStreamReader.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavStreamReader.cs new file mode 100644 index 0000000000..042b276c7e --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavStreamReader.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + /// + /// From https://archive.codeplex.com/?p=zxmak2 + /// + public class WavStreamReader + { + private Stream m_stream; + private WavHeader m_header = new WavHeader(); + + public WavStreamReader(Stream stream) + { + m_stream = stream; + m_header.Deserialize(stream); + } + + public WavHeader Header { get { return m_header; } } + + public int Count { get { return m_header.dataSize / m_header.fmtBlockAlign; } } + + public Int32 ReadNext() + { + // check - sample should be in PCM format + if (m_header.fmtCode != WAVE_FORMAT_PCM && + m_header.fmtCode != WAVE_FORMAT_IEEE_FLOAT) + { + throw new FormatException(string.Format( + "Not supported audio format: fmtCode={0}, bitDepth={1}", + m_header.fmtCode, + m_header.bitDepth)); + } + byte[] data = new byte[m_header.fmtBlockAlign]; + m_stream.Read(data, 0, data.Length); + if (m_header.fmtCode == WAVE_FORMAT_PCM) + { + // use first channel only + if (m_header.bitDepth == 8) + return getSamplePcm8(data, 0, 0); + if (m_header.bitDepth == 16) + return getSamplePcm16(data, 0, 0); + if (m_header.bitDepth == 24) + return getSamplePcm24(data, 0, 0); + if (m_header.bitDepth == 32) + return getSamplePcm32(data, 0, 0); + } + else if (m_header.fmtCode == WAVE_FORMAT_IEEE_FLOAT) + { + // use first channel only + if (m_header.bitDepth == 32) + return getSampleFloat32(data, 0, 0); + if (m_header.bitDepth == 64) + return getSampleFloat64(data, 0, 0); + } + throw new NotSupportedException(string.Format( + "Not supported audio format ({0}/{1} bit)", + m_header.fmtCode == WAVE_FORMAT_PCM ? "PCM" : "FLOAT", + m_header.bitDepth)); + } + + private Int32 getSamplePcm8(byte[] bufferRaw, int offset, int channel) + { + return bufferRaw[offset + channel] - 128; + } + + private Int32 getSamplePcm16(byte[] bufferRaw, int offset, int channel) + { + return BitConverter.ToInt16(bufferRaw, offset + 2 * channel); + } + + private Int32 getSamplePcm24(byte[] bufferRaw, int offset, int channel) + { + Int32 result; + int subOffset = offset + channel * 3; + if (BitConverter.IsLittleEndian) + { + result = ((sbyte)bufferRaw[2 + subOffset]) * 0x10000; + result |= bufferRaw[1 + subOffset] * 0x100; + result |= bufferRaw[0 + subOffset]; + } + else + { + result = ((sbyte)bufferRaw[0 + subOffset]) * 0x10000; + result |= bufferRaw[1 + subOffset] * 0x100; + result |= bufferRaw[2 + subOffset]; + } + return result; + } + + private Int32 getSamplePcm32(byte[] bufferRaw, int offset, int channel) + { + return BitConverter.ToInt32(bufferRaw, offset + 4 * channel); + } + + private Int32 getSampleFloat32(byte[] data, int offset, int channel) + { + float fSample = BitConverter.ToSingle(data, offset + 4 * channel); + // convert to 32 bit integer + return (Int32)(fSample * Int32.MaxValue); + } + + private Int32 getSampleFloat64(byte[] data, int offset, int channel) + { + double fSample = BitConverter.ToDouble(data, offset + 8 * channel); + // convert to 32 bit integer + return (Int32)(fSample * Int32.MaxValue); + } + + private const int WAVE_FORMAT_PCM = 1; /* PCM */ + private const int WAVE_FORMAT_IEEE_FLOAT = 3; /* IEEE float */ + private const int WAVE_FORMAT_ALAW = 6; /* 8-bit ITU-T G.711 A-law */ + private const int WAVE_FORMAT_MULAW = 7; /* 8-bit ITU-T G.711 µ-law */ + private const int WAVE_FORMAT_EXTENSIBLE = 0xFFFE; /* Determined by SubFormat */ + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md index 300abfd881..39c06a7c02 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/readme.md @@ -11,7 +11,7 @@ ZXHawk is still in dev but is potentially nearing a release state. * Full beeper and AY-3-3912 sound emulation * Tape device (datacorder) emulation * Internal 3" disk drive emulation (found in the +3 model) -* Currently supports the following tape image formats: *.tzx, *.tap +* Currently supports the following tape image formats: *.tzx, *.tap, *.pzx, *.csw, *.wav * Currently supports the following disk image formats (+3 only): *.dsk * Fully integrated into the Bizhawk ecosystem * See the ZXSpectrum menu for all available configuration options