From 2921e23bcaf0929843380689739516dec9479e4b Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Fri, 25 Oct 2019 17:09:07 -0400 Subject: [PATCH] Got audio rendering working. --- Common/BitStream.go | 5 +++++ Common/SceneInterface.go | 1 + Common/StreamReader.go | 33 +++++++++++++++++++++++++++++++++ Common/StreamWriter.go | 7 +++++++ Compression/Huffman.go | 9 ++++----- Compression/Wav.go | 34 ++++++++++++---------------------- Engine.go | 8 +++----- MPQStream.go | 2 +- README.md | 19 ------------------- 9 files changed, 66 insertions(+), 52 deletions(-) diff --git a/Common/BitStream.go b/Common/BitStream.go index 4a17d0aa..925c7b75 100644 --- a/Common/BitStream.go +++ b/Common/BitStream.go @@ -10,6 +10,7 @@ type BitStream struct { bitCount int } +// CreateBitStream creates a new BitStream func CreateBitStream(newData []byte) *BitStream { result := &BitStream{ data: newData, @@ -20,6 +21,7 @@ func CreateBitStream(newData []byte) *BitStream { return result } +// ReadBits reads the specified number of bits and returns the value func (v *BitStream) ReadBits(bitCount int) int { if bitCount > 16 { log.Panic("Maximum BitCount is 16") @@ -32,6 +34,7 @@ func (v *BitStream) ReadBits(bitCount int) int { return result } +// PeekByte returns the current byte without adjusting the position func (v *BitStream) PeekByte() int { if !v.EnsureBits(8) { return -1 @@ -39,6 +42,7 @@ func (v *BitStream) PeekByte() int { return v.current & 0xff } +// EnsureBits ensures that the specified number of bits are available func (v *BitStream) EnsureBits(bitCount int) bool { if bitCount <= v.bitCount { return true @@ -53,6 +57,7 @@ func (v *BitStream) EnsureBits(bitCount int) bool { return true } +// WasteBits dry-reads the specified number of bits func (v *BitStream) WasteBits(bitCount int) { v.current >>= bitCount v.bitCount -= bitCount diff --git a/Common/SceneInterface.go b/Common/SceneInterface.go index 6bd0f8a1..9a939654 100644 --- a/Common/SceneInterface.go +++ b/Common/SceneInterface.go @@ -4,6 +4,7 @@ import ( "github.com/hajimehoshi/ebiten" ) +// SceneInterface defines the function necessary for scene management type SceneInterface interface { Load() Unload() diff --git a/Common/StreamReader.go b/Common/StreamReader.go index 6b647101..0634f0dd 100644 --- a/Common/StreamReader.go +++ b/Common/StreamReader.go @@ -1,5 +1,11 @@ package Common +import ( + "bytes" + "encoding/binary" + "io" +) + // StreamReader allows you to read data from a byte array in various formats type StreamReader struct { data []byte @@ -40,6 +46,14 @@ func (v *StreamReader) GetWord() uint16 { return result } +// GetSWord returns a int16 word from the stream +func (v *StreamReader) GetSWord() int16 { + var result int16 + binary.Read(bytes.NewReader([]byte{v.data[v.position], v.data[v.position+1]}), binary.LittleEndian, &result) + v.position += 2 + return result +} + // GetDword returns a uint32 dword from the stream func (v *StreamReader) GetDword() uint32 { result := uint32(v.data[v.position]) @@ -49,3 +63,22 @@ func (v *StreamReader) GetDword() uint32 { v.position += 4 return result } + +// ReadByte implements io.ByteReader +func (v *StreamReader) ReadByte() (byte, error) { + return v.GetByte(), nil +} + +// Read implements io.Reader +func (v *StreamReader) Read(p []byte) (n int, err error) { + streamLength := v.GetSize() + for i := 0; ; i++ { + if v.GetPosition() >= streamLength { + return i, io.EOF + } + if i >= len(p) { + return i, nil + } + p[i] = v.GetByte() + } +} diff --git a/Common/StreamWriter.go b/Common/StreamWriter.go index cd4b418e..2c871a97 100644 --- a/Common/StreamWriter.go +++ b/Common/StreamWriter.go @@ -24,6 +24,12 @@ func (v *StreamWriter) PushWord(val uint16) { v.data = append(v.data, byte((val>>8)&0xFF)) } +// PushSWord writes a int16 word to the stream +func (v *StreamWriter) PushSWord(val int16) { + v.data = append(v.data, byte(val&0xFF)) + v.data = append(v.data, byte((val>>8)&0xFF)) +} + // PushDword writes a uint32 dword to the stream func (v *StreamWriter) PushDword(val uint32) { v.data = append(v.data, byte(val&0xFF)) @@ -32,6 +38,7 @@ func (v *StreamWriter) PushDword(val uint32) { v.data = append(v.data, byte((val>>24)&0xFF)) } +// GetBytes returns the the byte slice of the underlying data func (v *StreamWriter) GetBytes() []byte { return v.data } diff --git a/Compression/Huffman.go b/Compression/Huffman.go index b5a5b191..f86e64ab 100644 --- a/Compression/Huffman.go +++ b/Compression/Huffman.go @@ -30,7 +30,6 @@ package Compression import ( - "bytes" "log" "github.com/essial/OpenDiablo2/Common" @@ -345,7 +344,7 @@ func HuffmanDecompress(data []byte) []byte { tail := buildList(sPrime[comptype]) head := buildTree(tail) - var outputstream bytes.Buffer + outputstream := Common.CreateStreamWriter() bitstream := Common.CreateBitStream(data[1:]) var decoded int for true { @@ -356,11 +355,11 @@ func HuffmanDecompress(data []byte) []byte { break case 257: newvalue := bitstream.ReadBits(8) - outputstream.WriteByte(byte(newvalue)) + outputstream.PushByte(byte(newvalue)) tail = insertNode(tail, newvalue) break default: - outputstream.WriteByte(byte(decoded)) + outputstream.PushByte(byte(decoded)) break } if decoded == 256 { @@ -368,5 +367,5 @@ func HuffmanDecompress(data []byte) []byte { } } - return outputstream.Bytes() + return outputstream.GetBytes() } diff --git a/Compression/Wav.go b/Compression/Wav.go index 76c90a13..50f19c9d 100644 --- a/Compression/Wav.go +++ b/Compression/Wav.go @@ -1,10 +1,7 @@ package Compression import ( - "bufio" - "bytes" - "encoding/binary" - "io" + "github.com/essial/OpenDiablo2/Common" ) var sLookup = []int{ @@ -33,25 +30,21 @@ func WavDecompress(data []byte, channelCount int) []byte { Array1 := []int{0x2c, 0x2c} Array2 := make([]int, channelCount) - input := bytes.NewReader(data) - var output bytes.Buffer - outputWriter := bufio.NewWriter(&output) - input.ReadByte() + input := Common.CreateStreamReader(data) + output := Common.CreateStreamWriter() + input.GetByte() - shift, _ := input.ReadByte() + shift := input.GetByte() for i := 0; i < channelCount; i++ { - temp := int16(0) - binary.Read(input, binary.LittleEndian, &temp) + temp := input.GetSWord() Array2[i] = int(temp) - binary.Write(outputWriter, binary.LittleEndian, &temp) + output.PushSWord(temp) } channel := channelCount - 1 - pos, _ := input.Seek(0, io.SeekCurrent) - input.Seek(pos, io.SeekStart) - for pos < int64(input.Len()) { - value, _ := input.ReadByte() + for input.GetPosition() < input.GetSize() { + value := input.GetByte() if channelCount == 2 { channel = 1 - channel @@ -63,8 +56,7 @@ func WavDecompress(data []byte, channelCount int) []byte { if Array1[channel] != 0 { Array1[channel]-- } - d := int16(Array2[channel]) - binary.Write(outputWriter, binary.LittleEndian, &d) + output.PushSWord(int16(Array2[channel])) break case 1: Array1[channel] += 8 @@ -123,9 +115,7 @@ func WavDecompress(data []byte, channelCount int) []byte { } } Array2[channel] = temp3 - d := int16(temp3) - binary.Write(outputWriter, binary.LittleEndian, &d) - + output.PushSWord(int16(temp3)) Array1[channel] += sLookup2[value&0x1f] if Array1[channel] < 0 { @@ -137,5 +127,5 @@ func WavDecompress(data []byte, channelCount int) []byte { } } } - return output.Bytes() + return output.GetBytes() } diff --git a/Engine.go b/Engine.go index 785aa281..f154fc63 100644 --- a/Engine.go +++ b/Engine.go @@ -65,7 +65,7 @@ func CreateEngine() *Engine { result.mapMpqFiles() result.loadPalettes() result.loadSoundEntries() - audioContext, err := audio.NewContext(48000) + audioContext, err := audio.NewContext(22050) if err != nil { log.Fatal(err) } @@ -248,15 +248,13 @@ func (v *Engine) PlayBGM(song string) { v.bgmAudio.Close() } audioData := v.GetFile(song) - //audioData2, _ := ioutil.ReadFile(`C:\Users\lunat\Desktop\D2\Extracted\data\global\music\introedit.wav`) - //log.Printf("%d, %d", len(audioData), len(audioData2)) d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData)) if err != nil { log.Fatal(err) } - //s := audio.NewInfiniteLoop(d, int64(len(audioData))) + s := audio.NewInfiniteLoop(d, int64(len(audioData))) - v.bgmAudio, err = audio.NewPlayer(v.audioContext, d) + v.bgmAudio, err = audio.NewPlayer(v.audioContext, s) if err != nil { log.Fatal(err) } diff --git a/MPQStream.go b/MPQStream.go index 8cf71b41..8cccd431 100644 --- a/MPQStream.go +++ b/MPQStream.go @@ -198,7 +198,7 @@ func decompressMulti(data []byte, expectedLength uint32) []byte { panic("pk + mpqwav decompression not supported") case 0x81: sinput := Compression.HuffmanDecompress(data[1:]) - sinput = Compression.WavDecompress(sinput, 1) + sinput = Compression.WavDecompress(sinput, 2) tmp := make([]byte, len(sinput)) copy(tmp, sinput) return tmp diff --git a/README.md b/README.md index 3012c305..a1053d22 100644 --- a/README.md +++ b/README.md @@ -35,25 +35,6 @@ The following extensions are recommended for working with this project: * ms-vscode.go * defaltd.go-coverage-viewer -For the Go extension, it is recommended you add the following to settings.json: -```json - "go.languageServerExperimentalFeatures": { - "format": true, - "autoComplete": true, - "rename": true, - "goToDefinition": true, - "hover": true, - "signatureHelp": true, - "goToTypeDefinition": true, - "goToImplementation": true, - "documentSymbols": true, - "workspaceSymbols": true, - "findReferences": true, - "diagnostics": true, - "documentLink": true - }, -``` - You can get to it by going to settings Ctrl+,, expanding `Extensions` and selecting `Go configuration`, then clicking on `Edit in settings.json`. Just paste that section where appropriate.