importers bugfix, fix editor
3 files changed, 10 insertions(+), 628 deletions(-)

M editor/go.mod
M editor/main.go
R player/importxm.go => 
M editor/go.mod +4 -0
@@ 18,6 18,8 @@ require (
 
 require kristallos.ga/tut/player v0.0.0-00010101000000-000000000000
 
+require kristallos.ga/tut/player/importers/xm v0.0.0
+
 require kristallos.ga/tut/common v0.0.0
 
 require (

          
@@ 34,6 36,8 @@ require (
 //replace kristallos.ga/lib/debug => ../lib/debug
 replace kristallos.ga/tut/player => ../player
 
+replace kristallos.ga/tut/player/importers/xm => ../player/importers/xm
+
 replace kristallos.ga/tut/common => ../common
 
 // bb_local

          
M editor/main.go +6 -1
@@ 15,6 15,8 @@ import (
 	"runtime"
 	"runtime/pprof"
     "kristallos.ga/tut/player"
+    // A list ?
+    "kristallos.ga/tut/player/importers/xm"
     aobackend "kristallos.ga/tut/player/ao/backend/sdl"
 
 	//xg "kristallos.ga/xgui"

          
@@ 120,8 122,11 @@ func main() {
 		//m2 := l.load("tmp/testdata/new_file")
 
 		var m2 *player.Module
+		// XXX fixme ?
 		if _path.Ext(path) == ".xm" {
-			xmi := player.NewXmImporter()
+			//xmi := player.NewXmImporter()
+			//m2 = xmi.Load(path)
+			xmi := xm.NewXmImporter()
 			m2 = xmi.Load(path)
 		} else {
 			m2 = l.Load(path)

          
R player/importxm.go =>  +0 -627
@@ 1,627 0,0 @@ 
-package player
-
-import (
-	"bytes"
-	"encoding/binary"
-	"fmt"
-	"io"
-	"os"
-	"strings"
-)
-
-type XmInfo struct {
-	//x int
-	IDtext        [17]byte
-	ModuleName    [20]byte
-	_             byte
-	TrackerName   [20]byte
-	VersionNumber uint16
-}
-
-type XmHeader struct {
-	HeaderSize          uint32
-	SongLength          uint16
-	RestartPosition     uint16
-	NumberOfChannels    uint16
-	NumberOfPatterns    uint16
-	NumberOfInstruments uint16
-	Flags               uint16
-	DefaultTempo        uint16
-	DefaultBPM          uint16
-	//PatternOrderTable [256]byte // TODO
-}
-
-type XmPattern struct {
-	PatternHeaderLength   uint32
-	PackingType           byte   // always 0
-	NumberOfRows          uint16 // 1..256
-	PackedPatterndataSize uint16
-}
-
-type XmNote struct {
-	// (C-0 = 0 (xm docs; real value is C-0 = 1))
-	Note             byte // 0-71
-	Instrument       byte // 0-128
-	VolumeColumnByte byte
-	EffectType       byte
-	EffectParameter  byte
-}
-
-type XmInstrument struct {
-	InstrumentSize  uint32
-	InstrumentName  [22]byte
-	InstrumentType  byte // always 0
-	NumberOfSamples uint16
-}
-
-type XmSample struct {
-	SampleLength       uint32
-	SampleLoopStart    uint32
-	SampleLoopLength   uint32
-	Volume             byte
-	Finetune           byte // -16..15
-	Type               byte // Bit
-	Panning            byte // 0-255
-	RelativeNoteNumber byte // signed byte
-	_                  byte // reserved
-	SampleName         [22]byte
-}
-
-type XmImporter struct {
-	info        XmInfo
-	header      XmHeader
-	patterns    []XmPattern
-	patternData [][][]XmNote // use *xmnote?
-	instruments []XmInstrument
-	samples     [][]XmSample // inst -> sample
-	//sampleData [][]int16 // raw
-	sampleDataConv [][][][2]float64 // inst -> sample -> data
-}
-
-func NewXmImporter() *XmImporter {
-	xi := &XmImporter{
-		//samples: make([][]xmsample, 0),
-	}
-	//xi.info.x = 1
-	return xi
-}
-
-func (xi *XmImporter) Load(path string) *Module {
-	_log.Dbg("%F; path:", path)
-	f, err := os.Open(path)
-	if err != nil {
-		p("can't open file: path:", path)
-		panic(err)
-	}
-	//defer f.Close()
-
-	xi.Parse(f)
-
-	f.Close()
-
-	xmId := string(xi.info.IDtext[:])
-	p("xmId:", xmId)
-
-	xmName := string(xi.info.ModuleName[:])
-	p("xmName:", xmName)
-
-	xmVersionNumberMajor := (int(xi.info.VersionNumber) & 0xff00) >> 8 // high
-	xmVersionNumberMinor := int(xi.info.VersionNumber) & 0xff          // low
-
-	p("xmVersionNumberMajor", xmVersionNumberMajor)
-	p("xmVersionNumberMinor", xmVersionNumberMinor)
-
-	if !(xmVersionNumberMajor == 1 && xmVersionNumberMinor == 4) {
-		pp("not supported version?")
-	}
-	//pp(2)
-
-	var m *Module
-	if true {
-		title := xmName
-		bpm := int(xi.header.DefaultBPM)
-		ntracks := int(xi.header.NumberOfChannels)
-		if ntracks < 1 {
-			pp("error")
-		}
-
-		m = NewModule()
-		m.Info.Title = title
-		m.Bpm = bpm
-		m.Ntracks = ntracks
-
-		m.SetNumTracks(ntracks)
-
-		numPatterns := int(xi.header.NumberOfPatterns)
-		if numPatterns < 1 {
-			pp("error")
-		}
-
-		for i := 0; i < numPatterns; i++ {
-			numRows := int(xi.patterns[i].NumberOfRows)
-			pt := m.AddNewPattern(numRows)
-			dx, dy := pt.Dim()
-			p("dim:", dx, dy)
-
-			// Fill pattern
-			for row := 0; row < pt.Nrows; row++ {
-				for tr := 0; tr < pt.Ntracks; tr++ {
-					p("row:", row, "tr:", tr)
-
-					xnote := xi.patternData[i][row][tr]
-					if xnote.Note == 0 {
-						// No note, skipping
-						continue
-					}
-
-					c := pt.GetCellAt(tr, row)
-
-					noteNum := int(xnote.Note) - 1
-					note := GetNoteByNum(noteNum)
-
-					c.Note = note
-
-					instrument := int(xnote.Instrument)
-					c.InstrumentNum = &instrument
-
-					volCol := int(xnote.VolumeColumnByte)
-
-					if volCol != 0 {
-						// Scale volume to 0..80h range
-						volume := (volCol - 0x10) * 2
-
-						c.Vol = &volume
-					}
-				}
-			}
-		}
-
-		// Load instruments
-		numInstruments := int(xi.header.NumberOfInstruments)
-		for i := 0; i < numInstruments; i++ {
-			p("load instrument i:", i)
-			inst := m.GetInstrument(i)
-
-			numSamples := int(xi.instruments[i].NumberOfSamples)
-
-			for j := 0; j < numSamples; j++ {
-				xmsample := xi.samples[i][j]
-				sd := xi.sampleDataConv[i][j]
-
-				//smp := inst.loadSample(j, "/tmp/s1.raw")
-				smp := inst.LoadSampleFromData(j, sd)
-				smp.Num = j
-				smp.Name = string(xmsample.SampleName[:])
-
-				// Read Type Bit
-				loop := xmsample.Type & 0x3
-				if loop == 0 {
-
-				} else if loop == 1 {
-					smp.LoopType = LoopType_Forward
-				} else if loop == 2 {
-					smp.LoopType = LoopType_PingPong
-				} else {
-					pp("error")
-				}
-
-				//smp.loopType = LoopType_Forward
-			}
-		}
-
-		m.AddNewOrder(0)
-		//m.addNewOrder(1)
-
-	}
-
-	_log.Dbg("done %F")
-
-	return m
-}
-
-func (xi *XmImporter) Parse(f *os.File) {
-	_log.Dbg("%F")
-
-	// Info
-
-	//info := xminfo{}
-	info := &xi.info
-	data := readNextBytes(f, 60)
-
-	p("data:")
-	p(data)
-	p(len(data))
-
-	buffer := bytes.NewBuffer(data)
-	err := binary.Read(buffer, binary.LittleEndian, info)
-	if err != nil {
-		pp("binary.Read failed", err)
-	}
-
-	fmt.Printf("parsed data:\n%+v\n", info)
-
-	// Header
-
-	p("parsing header...")
-	data = readNextBytes(f, 20) //+256)
-
-	p("data:")
-	p(data)
-	p(len(data))
-
-	buffer = bytes.NewBuffer(data)
-	err = binary.Read(buffer, binary.LittleEndian, &xi.header)
-	if err != nil {
-		pp("binary.Read failed", err)
-	}
-
-	fmt.Printf("parsed data:\n%+v\n", xi.header)
-
-	numInst := int(xi.header.NumberOfInstruments)
-	xi.instruments = make([]XmInstrument, 0)
-	//pp(numInst, xi.instruments)
-	xi.samples = make([][]XmSample, 0)
-	xi.sampleDataConv = make([][][][2]float64, 0)
-
-	// Skip pattern order
-	nominalHeaderSize := 20
-	diff := int(xi.header.HeaderSize) - nominalHeaderSize
-	//pp(diff)
-	p("skip pattern order...")
-	_ = readNextBytes(f, diff)
-
-	// Patterns
-
-	numCh := int(xi.header.NumberOfChannels)
-	numPt := int(xi.header.NumberOfPatterns)
-	// Init PatternData
-	xi.patternData = make([][][]XmNote, numPt)
-
-	p("parsing patterns...")
-	for i := 0; i < numPt; i++ {
-
-		p("read pattern n:", i)
-		data = readNextBytes(f, 9)
-		p("data:", data)
-		buffer = bytes.NewBuffer(data)
-		pt := XmPattern{}
-		err = binary.Read(buffer, binary.LittleEndian, &pt)
-		if err != nil {
-			pp("binary.Read failed", err)
-		}
-		fmt.Printf("parsed data:\n%+v\n", pt)
-		xi.patterns = append(xi.patterns, pt)
-
-		pdSize := int(pt.PackedPatterndataSize)
-		_ = pdSize
-		//pd := readNextBytes(f, pdSize)
-		//_ = pd
-
-		// Decode patterndata
-
-		//pd := &xi.patternData[i]
-		numRows := int(xi.patterns[i].NumberOfRows)
-		pd := make([][]XmNote, numRows)
-		for i := range pd {
-			pd[i] = make([]XmNote, numCh)
-		}
-
-		// Set pd
-		//xi.patternData[i] = pd
-		//pp(pd[0][0])
-
-		//for i := 0; i < pdSize; i++ {
-		for row := 0; row < numRows; row++ {
-			for ch := 0; ch < numCh; ch++ {
-				p("read note...")
-
-				xnote := XmNote{}
-
-				//data = pd[i : 5]
-				var note byte
-				//if err := binary.Read(f, binary.LittleEndian, &note); err != nil {
-				//	panic(err)
-				//}
-				readBin(f, 1, &note, "note")
-				//pp(note)
-				offset := 1
-
-				if note&0x80 != 0 {
-					println("packed")
-					// Packed
-					if note&0x01 != 0 {
-						readBin(f, 1, &xnote.Note, "p_note")
-						offset++
-					}
-					if note&0x02 != 0 {
-						readBin(f, 1, &xnote.Instrument, "p_instrument")
-						offset++
-					}
-					if note&0x04 != 0 {
-						readBin(f, 1, &xnote.VolumeColumnByte, "p_volumecolumntbyte")
-						offset++
-					}
-					if note&0x08 != 0 {
-						readBin(f, 1, &xnote.EffectType, "p_effecttype")
-						offset++
-					}
-					if note&0x10 != 0 {
-						readBin(f, 1, &xnote.EffectParameter, "p_effectparameter")
-						offset++
-					}
-				} else {
-					// Unpacked
-					println("unpacked")
-					xnote.Note = note
-					readBin(f, 1, &xnote.Instrument, "u_instrument")
-					readBin(f, 1, &xnote.VolumeColumnByte, "u_volumecolumnbyte")
-					readBin(f, 1, &xnote.EffectType, "u_effecttype")
-					readBin(f, 1, &xnote.EffectParameter, "u_effectparameter")
-					offset += 4
-					// pp(3)
-				}
-
-				pd[row][ch] = xnote
-
-				p("row:", row, "ch:", ch)
-				p("offset:", offset)
-				pv(xnote)
-				//pp(2)
-			}
-		}
-
-		// Set
-		xi.patternData[i] = pd
-		//pdump(pd)
-		//pp(3)
-	}
-
-	// Instruments
-
-	println("parsing instruments...")
-	p("numInst:", numInst)
-	for i := 0; i < numInst; i++ {
-		inst := XmInstrument{}
-		readBin(f, 29, &inst, "instrument")
-		pv(inst)
-		instName := string(inst.InstrumentName[:])
-		p("instName:", instName)
-
-		xi.instruments = append(xi.instruments, inst)
-		//xi.instruments[i] = inst
-
-		//pp(2)
-		numSamples := int(inst.NumberOfSamples)
-
-		if numSamples == 0 {
-			println("no samples, continue")
-			continue
-		}
-
-		//xi.samples[i] = make([]xmsample, numSamples)
-		//xi.samples[i] = make([]xmsample, 0)
-		slot := make([]XmSample, 0)
-		xi.samples = append(xi.samples, slot)
-
-		/*
-			var sampleHeaderSize uint32
-			readBin(f, 4, &sampleHeaderSize, "sampleHeaderSize")
-			p(sampleHeaderSize)
-			pp(3)
-		*/
-
-		// Skip the second half on the instrument
-		//n := 214
-		n := 263 - 29 // 263 = inst.InstrumentSize
-		_ = readNextBytes(f, n)
-
-		// Read samples
-
-		for j := 0; j < numSamples; j++ {
-			println("parsing samples...")
-			smp := XmSample{}
-			readBin(f, 40, &smp, "sample")
-			pv(smp)
-
-			//xi.samples[i][j] = smp
-			xi.samples[i] = append(xi.samples[i], smp)
-
-			smpName := string(smp.SampleName[:])
-			p("smpName:", smpName)
-			//pp(2)
-
-			// Read Type Bit
-			dWidth := 1
-			if smp.Type&(1<<4) != 0 {
-				dWidth = 2 // 16bit
-			}
-			p("dWidth:", dWidth)
-			//pp(2)
-
-			// Read sample data
-			println("parsing sample data...")
-			smpLength := int(smp.SampleLength)
-			p("smpLength:", smpLength)
-
-			sdSize := smpLength
-			sdSizeSamples := smpLength / dWidth
-			p("sdSize:", sdSize)
-			p("sdSizeSamples:", sdSizeSamples)
-			//sd := readNextBytes(f, sdSize)
-			//pp(2)
-
-			if dWidth == 1 {
-				//pp(8)
-			}
-
-			var _ = `
-			
-			// Decode sample data
-			sampleOrig8 := make([]byte, sdSizeSamples) // original 8bit data
-			sample := make([]int16, sdSizeSamples)
-			old := int16(0)
-			for k := 0; k < sdSizeSamples; k++ {
-				var rawS int16
-				if dWidth == 2 {
-					readBin(f, 2, &rawS, "rawS")
-				} else {
-					// Upscale to 16bit
-					var tmpRawS byte
-					readBin(f, 1, &tmpRawS, "tmpRawS")
-					rawS = int16(tmpRawS)
-					sampleOrig8[k] = tmpRawS
-				}
-				//s := int(rawS)
-				s := rawS
-				new_ := s + old
-				sample[k] = new_
-				old = new_
-				//pp(5)
-			}
-			`
-			_ = `
-			// Decode sample data
-			sampleOrig8 := make([]int8, sdSizeSamples) // original 8bit data
-			sample := make([]int8, sdSizeSamples)
-			old := int8(0)
-			for k := 0; k < sdSizeSamples; k++ {
-				var rawS int8
-				readBin(f, 1, &rawS, "rawS")
-				//s := int(rawS)
-				s := rawS
-				new_ := s + old
-				sample[k] = new_
-				old = new_
-				//pp(5)
-			}
-			`
-
-			// Decode sample data
-			sampleOrig8 := make([]int8, sdSizeSamples) // original 8bit data
-			sample := make([]int16, sdSizeSamples)
-			old := int16(0)
-			old8 := int8(0)
-			for k := 0; k < sdSizeSamples; k++ {
-				if dWidth == 2 {
-					var rawS int16
-					readBin(f, 2, &rawS, "rawS")
-					s := rawS
-					new_ := s + old
-					sample[k] = new_
-					old = new_
-				} else {
-					var tmpRawS int8
-					readBin(f, 1, &tmpRawS, "tmpRawS")
-					//sampleOrig8[k] = tmpRawS // XXX packed data
-					s := tmpRawS
-					new_ := s + old8
-					sample[k] = int16(new_) << 8 // to 16bit value
-					sampleOrig8[k] = new_        // unpacked
-					old8 = new_
-				}
-
-				//pp(5)
-			}
-
-			//ioutil.WriteFile("/tmp/s1.raw", sample, 0644)
-			name := smpName
-			name = strings.ReplaceAll(name, "\x00", "\x20")
-			name = strings.ReplaceAll(name, "/", "_")
-			pathPrefix := fmt.Sprintf("/tmp/smp_%d_%s", j, name)
-			path := pathPrefix + ".raw"
-			//fmt.Printf("path: %#v\n", path)
-			//path = "/tmp/1.raw"
-			//p("pathPrefix:", pathPrefix)
-			p("path:", path)
-			//pp(2)
-
-			outf, err := os.Create(path)
-			if err != nil {
-				panic(err)
-			}
-			err = binary.Write(outf, binary.LittleEndian, sample)
-			if err != nil {
-				panic(err)
-			}
-			outf.Close()
-			// Save orig 8bit data
-			if dWidth == 1 {
-				outf, err := os.Create(pathPrefix + "_8bit_orig.raw")
-				if err != nil {
-					panic(err)
-				}
-				err = binary.Write(outf, binary.LittleEndian, sampleOrig8)
-				if err != nil {
-					panic(err)
-				}
-				outf.Close()
-			}
-
-			sampleConv := make([][2]float64, sdSizeSamples)
-			for i, _ := range sampleConv {
-				//if dWidth == 2 {
-				// Mono to stereo
-				vf := I16tof(int(sample[i]))
-				sampleConv[i][0] = vf
-				sampleConv[i][1] = vf
-				//} else {
-				//	pp("8bit samples not supported")
-				//}
-			}
-			//pp(4)
-
-			//xi.sampleDataConv[i] = make([][][2]float64, 0)
-			slot := make([][][2]float64, 0)
-			xi.sampleDataConv = append(xi.sampleDataConv, slot)
-			xi.sampleDataConv[i] = append(xi.sampleDataConv[i], sampleConv)
-			//pdump(xi.sampleDataConv[i])
-			//xi.sampleDataConv[i][j] = sampleConv
-		}
-	}
-
-	_log.Dbg("done %F")
-
-}
-
-func readBin(file *os.File, number int, data interface{}, name string) {
-	println("readBin")
-	if name != "" {
-		println("name:", name)
-	}
-	readdata := readNextBytes(file, number)
-	p("readdata:", readdata)
-	buffer := bytes.NewBuffer(readdata)
-	if err := binary.Read(buffer, binary.LittleEndian, data); err != nil {
-		panic(err)
-	}
-}
-
-func readBin2(r io.Reader, data interface{}) {
-	if err := binary.Read(r, binary.LittleEndian, data); err != nil {
-		panic(err)
-	}
-}
-
-func readNextBytes(file *os.File, number int) []byte {
-	bytes := make([]byte, number)
-
-	getOffset := func() int64 {
-		offset, err := file.Seek(0, os.SEEK_CUR)
-		if err != nil {
-			panic(err)
-		}
-		// Seek back?
-		file.Seek(offset, os.SEEK_SET)
-		return offset
-	}
-
-	off1 := getOffset()
-	fmt.Printf("read bytes from: %d (0x%x) number: %d until: %d (0x%x)\n",
-		off1, off1, number, int(off1)+number, int(off1)+number)
-	_, err := file.Read(bytes)
-	if err != nil {
-		panic(err)
-	}
-
-	return bytes
-}