sointu/tracker/generate/main.go
2023-10-20 16:36:09 +03:00

137 lines
3.6 KiB
Go

//go:build ignore
// +build ignore
package main
import (
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/vsariola/sointu/tracker"
)
type riffVisitor interface {
Enter(listType string)
Leave(listType string)
Visit(filePos int, chunkType string, data []byte)
}
type gmDlsVisitor struct {
outputFile io.Writer
entry tracker.GmDlsEntry
dataLength int
count int
}
func (v *gmDlsVisitor) Enter(listType string) {
if listType == "wave" {
v.entry = tracker.GmDlsEntry{}
v.dataLength = 0
}
}
func (v *gmDlsVisitor) Leave(listType string) {
if listType == "wave" {
if v.entry.LoopLength == 0 {
v.entry.LoopStart = v.dataLength/2 - 1
v.entry.LoopLength = 1
}
if v.entry.Name == "" {
v.entry.Name = fmt.Sprintf("#%v", v.count)
}
fmt.Fprintf(v.outputFile, "\t{Start: %v, LoopStart: %v, LoopLength: %v, SuggestedTranspose: %v, Name: \"%v\"},\n", v.entry.Start, v.entry.LoopStart, v.entry.LoopLength, v.entry.SuggestedTranspose, v.entry.Name)
v.count++
}
}
func (v *gmDlsVisitor) Visit(filePos int, chunkType string, data []byte) {
switch chunkType {
case "wsmp":
v.entry.SuggestedTranspose = 60 - int(binary.LittleEndian.Uint16(data[4:6]))
numLoops := binary.LittleEndian.Uint32(data[16:20])
if numLoops > 0 {
v.entry.LoopStart = int(binary.LittleEndian.Uint32(data[28:32]))
v.entry.LoopLength = int(binary.LittleEndian.Uint32(data[32:36]))
}
case "data":
v.entry.Start = filePos / 2
v.dataLength = len(data)
case "INAM":
v.entry.Name = string(data[:len(data)-1])
}
}
func readChunk(filePos int, reader io.Reader, visitor riffVisitor) int {
var chunkType [4]byte
n, err := io.ReadFull(reader, chunkType[:])
check(err)
if n < 4 {
panic("did not get full 4 bytes for a chunktype")
}
filePos += n
chunkTypeString := string(chunkType[:])
var chunkLength int32
check(binary.Read(reader, binary.LittleEndian, &chunkLength))
filePos += 4
if chunkTypeString == "RIFF" || chunkTypeString == "LIST" {
end := filePos + int(chunkLength)
var listType [4]byte
n, err := io.ReadFull(reader, listType[:])
check(err)
if n < 4 {
panic("did not get full 4 bytes for a subchunkname")
}
filePos += n
listTypeString := string(listType[:])
visitor.Enter(listTypeString)
for filePos < end {
filePos = readChunk(filePos, reader, visitor)
}
visitor.Leave(listTypeString)
} else {
data := make([]byte, chunkLength)
n, err := reader.Read(data)
check(err)
if n < int(chunkLength) {
panic(fmt.Sprintf("chunk %v was supposed to be %v bytes, got %v bytes", chunkTypeString, chunkLength, n))
}
visitor.Visit(filePos, chunkTypeString, data)
filePos += n
}
if chunkLength&1 == 1 {
io.CopyN(ioutil.Discard, reader, 1)
filePos++
}
return filePos
}
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
inputFile, err := os.Open("C:\\Windows\\System32\\drivers\\gm.dls")
check(err)
defer inputFile.Close()
//_, myname, _, _ := runtime.Caller(0)
//outputFilePath := path.Join(path.Dir(myname), "gmdlsentries.go")
//check(err)
outputFile, err := os.Create("gmdlsentries.go")
check(err)
defer outputFile.Close()
fmt.Fprintln(outputFile, "package tracker")
fmt.Fprintln(outputFile, "")
fmt.Fprintln(outputFile, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(outputFile, "")
fmt.Fprintln(outputFile, "// GmDlsEntries is a list of all samples in the gm.dls file. Do not modify")
fmt.Fprintln(outputFile, "// during runtime.")
fmt.Fprintln(outputFile, "var GmDlsEntries = []GmDlsEntry{")
readChunk(0, inputFile, &gmDlsVisitor{outputFile: outputFile})
fmt.Fprintln(outputFile, "}")
}