137 lines
2.6 KiB
Go
137 lines
2.6 KiB
Go
//go:build !disable_format_mp3 && !disable_codec_lame && cgo
|
|
|
|
package mp3
|
|
|
|
/*
|
|
#cgo LDFLAGS: -lmp3lame
|
|
#include <lame/lame.h>
|
|
*/
|
|
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
|
|
}
|