172 lines
3.7 KiB
Go
172 lines
3.7 KiB
Go
package guess
|
|
|
|
import (
|
|
"errors"
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format"
|
|
"io"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
type NullFormat struct {
|
|
name string
|
|
}
|
|
|
|
func (f NullFormat) Name() string {
|
|
return f.name
|
|
}
|
|
|
|
func (f NullFormat) DecoderDescription() string {
|
|
return "null"
|
|
}
|
|
|
|
func (f NullFormat) EncoderDescription() string {
|
|
return "null"
|
|
}
|
|
|
|
func (f NullFormat) Open(io.ReadSeekCloser) (audio.Source, error) {
|
|
return nil, errors.New("null format")
|
|
}
|
|
|
|
func (f NullFormat) OpenAnalyzer(io.ReadSeekCloser) (audio.Source, format.AnalyzerChannel, error) {
|
|
return nil, nil, errors.New("null format")
|
|
}
|
|
|
|
func (f NullFormat) Encode(audio.Source, io.WriteCloser, map[string]interface{}) error {
|
|
return errors.New("null format")
|
|
}
|
|
|
|
func (f NullFormat) Identify([format.IdentifyPeekBytes]byte, string) bool {
|
|
return false
|
|
}
|
|
|
|
var knownFormats []format.Format
|
|
|
|
func AddFormat(format format.Format) {
|
|
knownFormats = append(knownFormats, format)
|
|
}
|
|
|
|
func GetFormat(name string) format.Format {
|
|
for _, formatEntry := range knownFormats {
|
|
if formatEntry.Name() == name {
|
|
return formatEntry
|
|
}
|
|
}
|
|
|
|
return NullFormat{
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
func GetDecoder(name string) format.Decoder {
|
|
for _, formatEntry := range knownFormats {
|
|
if decoder, ok := formatEntry.(format.Decoder); ok && formatEntry.Name() == name {
|
|
return decoder
|
|
}
|
|
}
|
|
|
|
return NullFormat{
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
func GetAnalyzerDecoder(name string) format.AnalyzerDecoder {
|
|
for _, formatEntry := range knownFormats {
|
|
if decoder, ok := formatEntry.(format.AnalyzerDecoder); ok && formatEntry.Name() == name {
|
|
return decoder
|
|
}
|
|
}
|
|
|
|
return NullFormat{
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
func GetEncoder(name string) format.Encoder {
|
|
for _, formatEntry := range knownFormats {
|
|
if encoder, ok := formatEntry.(format.Encoder); ok && formatEntry.Name() == name {
|
|
return encoder
|
|
}
|
|
}
|
|
|
|
return NullFormat{
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
func GetDecoders(r io.ReadSeekCloser, pathName string) (decoders []format.Decoder, err error) {
|
|
extension := strings.ToLower(strings.TrimPrefix(path.Ext(pathName), "."))
|
|
|
|
var startOffset int64
|
|
startOffset, err = r.Seek(0, io.SeekCurrent)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var peek [format.IdentifyPeekBytes]byte
|
|
if _, err = r.Read(peek[:]); err != nil {
|
|
return
|
|
}
|
|
if _, err = r.Seek(startOffset, io.SeekStart); err != nil {
|
|
return
|
|
}
|
|
|
|
for _, formatEntry := range knownFormats {
|
|
if decoder, ok := formatEntry.(format.Decoder); ok {
|
|
if decoder.Identify(peek, extension) {
|
|
decoders = append(decoders, decoder)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(decoders) == 0 {
|
|
return nil, errors.New("could not find decoder")
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func Open(r io.ReadSeekCloser, decoders []format.Decoder) (source audio.Source, err error) {
|
|
var startOffset int64
|
|
startOffset, err = r.Seek(0, io.SeekCurrent)
|
|
|
|
for _, decoder := range decoders {
|
|
if _, err = r.Seek(startOffset, io.SeekStart); err != nil {
|
|
return
|
|
}
|
|
source, err = decoder.Open(r)
|
|
if source != nil && err == nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
//seek back
|
|
if _, err = r.Seek(startOffset, io.SeekStart); err != nil {
|
|
return
|
|
}
|
|
return nil, errors.New("could not open stream")
|
|
}
|
|
|
|
func OpenAnalyzer(r io.ReadSeekCloser, decoders []format.Decoder) (source audio.Source, analyzerChannel format.AnalyzerChannel, err error) {
|
|
var startOffset int64
|
|
startOffset, err = r.Seek(0, io.SeekCurrent)
|
|
|
|
for _, decoder := range decoders {
|
|
if analyzer, ok := decoder.(format.AnalyzerDecoder); ok {
|
|
if _, err = r.Seek(startOffset, io.SeekStart); err != nil {
|
|
return
|
|
}
|
|
source, analyzerChannel, err = analyzer.OpenAnalyzer(r)
|
|
if source != nil && err == nil {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
//seek back
|
|
if _, err = r.Seek(startOffset, io.SeekStart); err != nil {
|
|
return
|
|
}
|
|
return nil, nil, errors.New("could not open stream analyzer")
|
|
}
|