//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, "}") }