//go:build !disable_format_mp3 && !disable_codec_lame && cgo package mp3 /* #cgo LDFLAGS: -lmp3lame #include */ import "C" import ( "errors" "fmt" "git.gammaspectra.live/S.O.N.G/Kirika/audio" "github.com/viert/go-lame" "io" "runtime" "unsafe" ) func (f Format) EncoderDescription() string { //TODO: move version fetch to viert/go-lame return fmt.Sprintf("LAME %s (viert/go-lame)", C.GoString(C.get_lame_version())) } func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[string]interface{}) error { var vbr = true var bitrate = 0 if options != nil { var val interface{} var ok bool var intVal int var int64Val int64 var strVal string if val, ok = options["bitrate"]; ok { if strVal, ok = val.(string); ok { switch strVal { case "v0": vbr = true bitrate = 0 case "v1": vbr = true bitrate = 1 case "v2": vbr = true bitrate = 2 case "v3": vbr = true bitrate = 3 case "v4": vbr = true bitrate = 4 case "v5": vbr = true bitrate = 5 case "v6": vbr = true bitrate = 6 case "v7": vbr = true bitrate = 7 case "v8": vbr = true bitrate = 8 case "v9": vbr = true bitrate = 9 case "320k": vbr = false bitrate = 320 case "256k": vbr = false bitrate = 256 case "192k": vbr = false bitrate = 192 case "128k": vbr = false bitrate = 128 default: return fmt.Errorf("unknown setting bitrate=%s", strVal) } } else if intVal, ok = val.(int); ok { vbr = false bitrate = intVal } else if int64Val, ok = val.(int64); ok { vbr = false bitrate = int(int64Val) } } } encoder := lame.NewEncoder(writer) if encoder == nil { return errors.New("could not create encoder") } defer encoder.Close() if err := encoder.SetNumChannels(source.GetChannels()); err != nil { return err } if err := encoder.SetInSamplerate(source.GetSampleRate()); err != nil { return err } encoder.SetWriteID3TagAutomatic(false) if vbr { if err := encoder.SetVBR(lame.VBRDefault); err != nil { return err } if err := encoder.SetVBRQuality(float64(bitrate)); err != nil { return err } } else { if err := encoder.SetVBR(lame.VBROff); err != nil { return err } if err := encoder.SetBrate(bitrate); err != nil { return err } } for block := range source.ToInt16().GetBlocks() { _, err := encoder.Write(unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(block))), len(block)*2)) runtime.KeepAlive(block) if err != nil { return err } } encoder.Flush() return nil }