Removed main dependencies, output float32 instead of bytes, rename package

This commit is contained in:
DataHoarder 2022-12-01 10:20:34 +01:00
parent c4ad2cec0a
commit 42e7219a3f
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
18 changed files with 59 additions and 139 deletions

View file

@ -1,6 +1,6 @@
# go-mp3
[![GoDoc](https://godoc.org/github.com/hajimehoshi/go-mp3?status.svg)](http://godoc.org/github.com/hajimehoshi/go-mp3)
[![GoDoc](https://godoc.org/git.gammaspectra.live/S.O.N.G/go-mp3?status.svg)](http://godoc.org/git.gammaspectra.live/S.O.N.G/go-mp3)
An MP3 decoder in pure Go based on [PDMP3](https://github.com/technosaurus/PDMP3).

View file

@ -17,12 +17,12 @@ package mp3
import (
"bytes"
"io"
"io/ioutil"
"os"
"testing"
)
func BenchmarkDecode(b *testing.B) {
buf, err := ioutil.ReadFile("example/classic.mp3")
buf, err := os.ReadFile("testdata/classic.mp3")
if err != nil {
b.Fatal(err)
}
@ -35,8 +35,12 @@ func BenchmarkDecode(b *testing.B) {
if err != nil {
b.Fatal(err)
}
if _, err := ioutil.ReadAll(d); err != nil {
b.Fatal(err)
data := make([]float32, 0, 64)
for {
if _, err := d.ReadFloat(data); err != nil {
b.Fatal(err)
}
}
}
}

View file

@ -18,23 +18,23 @@ import (
"errors"
"io"
"github.com/hajimehoshi/go-mp3/internal/consts"
"github.com/hajimehoshi/go-mp3/internal/frame"
"github.com/hajimehoshi/go-mp3/internal/frameheader"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/consts"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/frame"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/frameheader"
)
// A Decoder is a MP3-decoded stream.
//
// Decoder decodes its underlying source on the fly.
type Decoder struct {
source *source
sampleRate int
length int64
frameStarts []int64
buf []byte
frame *frame.Frame
pos int64
bytesPerFrame int64
source *source
sampleRate int
length int64
frameStarts []int64
buf []float32
frame *frame.Frame
pos int64
samplesPerFrame int64
}
func (d *Decoder) readFrame() error {
@ -54,8 +54,7 @@ func (d *Decoder) readFrame() error {
return nil
}
// Read is io.Reader's Read.
func (d *Decoder) Read(buf []byte) (int, error) {
func (d *Decoder) ReadFloat(buf []float32) (int, error) {
for len(d.buf) == 0 {
if err := d.readFrame(); err != nil {
return 0, err
@ -94,7 +93,7 @@ func (d *Decoder) Seek(offset int64, whence int) (int64, error) {
d.pos = npos
d.buf = nil
d.frame = nil
f := d.pos / d.bytesPerFrame
f := d.pos / d.samplesPerFrame
// If the frame is not first, read the previous ahead of reading that
// because the previous frame can affect the targeted frame.
if f > 0 {
@ -108,7 +107,7 @@ func (d *Decoder) Seek(offset int64, whence int) (int64, error) {
if err := d.readFrame(); err != nil {
return 0, err
}
d.buf = d.buf[d.bytesPerFrame+(d.pos%d.bytesPerFrame):]
d.buf = d.buf[d.samplesPerFrame+(d.pos%d.samplesPerFrame):]
} else {
if _, err := d.source.Seek(d.frameStarts[f], 0); err != nil {
return 0, err
@ -163,8 +162,8 @@ func (d *Decoder) ensureFrameStartsAndLength() error {
return err
}
d.frameStarts = append(d.frameStarts, pos)
d.bytesPerFrame = int64(h.BytesPerFrame())
l += d.bytesPerFrame
d.samplesPerFrame = int64(h.SamplesPerFrame())
l += d.samplesPerFrame
framesize, err := h.FrameSize()
if err != nil {

Binary file not shown.

View file

@ -1,65 +0,0 @@
// Copyright 2017 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"log"
"os"
"time"
"github.com/hajimehoshi/oto/v2"
"github.com/hajimehoshi/go-mp3"
)
func run() error {
f, err := os.Open("classic.mp3")
if err != nil {
return err
}
defer f.Close()
d, err := mp3.NewDecoder(f)
if err != nil {
return err
}
c, ready, err := oto.NewContext(d.SampleRate(), 2, 2)
if err != nil {
return err
}
<-ready
p := c.NewPlayer(d)
defer p.Close()
p.Play()
fmt.Printf("Length: %d[bytes]\n", d.Length())
for {
time.Sleep(time.Second)
if !p.IsPlaying() {
break
}
}
return nil
}
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}

Binary file not shown.

4
go.mod
View file

@ -1,5 +1,3 @@
module github.com/hajimehoshi/go-mp3
module git.gammaspectra.live/S.O.N.G/go-mp3
go 1.14
require github.com/hajimehoshi/oto/v2 v2.3.1

4
go.sum
View file

@ -1,4 +0,0 @@
github.com/hajimehoshi/oto/v2 v2.3.1 h1:qrLKpNus2UfD674oxckKjNJmesp9hMh7u7QCrStB3Rc=
github.com/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -16,8 +16,6 @@ package bits_test
import (
"testing"
. "github.com/hajimehoshi/go-mp3/internal/bits"
)
func TestBits(t *testing.T) {

View file

@ -19,12 +19,12 @@ import (
"io"
"math"
"github.com/hajimehoshi/go-mp3/internal/bits"
"github.com/hajimehoshi/go-mp3/internal/consts"
"github.com/hajimehoshi/go-mp3/internal/frameheader"
"github.com/hajimehoshi/go-mp3/internal/imdct"
"github.com/hajimehoshi/go-mp3/internal/maindata"
"github.com/hajimehoshi/go-mp3/internal/sideinfo"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/bits"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/consts"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/frameheader"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/imdct"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/maindata"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/sideinfo"
)
var (
@ -115,8 +115,8 @@ func (f *Frame) SamplingFrequency() (int, error) {
return f.header.SamplingFrequencyValue()
}
func (f *Frame) Decode() []byte {
out := make([]byte, f.header.BytesPerFrame())
func (f *Frame) Decode() []float32 {
out := make([]float32, f.header.SamplesPerFrame())
nch := f.header.NumberOfChannels()
for gr := 0; gr < f.header.Granules(); gr++ {
for ch := 0; ch < nch; ch++ {
@ -128,7 +128,7 @@ func (f *Frame) Decode() []byte {
f.antialias(gr, ch)
f.hybridSynthesis(gr, ch)
f.frequencyInversion(gr, ch)
f.subbandSynthesis(gr, ch, out[consts.SamplesPerGr*4*gr:])
f.subbandSynthesis(gr, ch, out[consts.SamplesPerGr*gr:])
}
}
return out
@ -621,7 +621,7 @@ var synthDtbl = [512]float32{
0.000015259, 0.000015259, 0.000015259, 0.000015259,
}
func (f *Frame) subbandSynthesis(gr int, ch int, out []byte) {
func (f *Frame) subbandSynthesis(gr int, ch int, out []float32) {
u_vec := make([]float32, 512)
s_vec := make([]float32, 32)
@ -653,29 +653,19 @@ func (f *Frame) subbandSynthesis(gr int, ch int, out []byte) {
for j := 0; j < 512; j += 32 {
sum += u_vec[j+i]
}
// sum now contains time sample 32*ss+i. Convert to 16-bit signed int
samp := int(sum * 32767)
if samp > 32767 {
samp = 32767
} else if samp < -32767 {
samp = -32767
}
s := int16(samp)
idx := 4 * (32*ss + i)
idx := 2 * (32*ss + i)
if nch == 1 {
// We always run in stereo mode and duplicate channels here for mono.
out[idx] = byte(s)
out[idx+1] = byte(s >> 8)
out[idx+2] = byte(s)
out[idx+3] = byte(s >> 8)
out[idx] = sum
out[idx+1] = sum
continue
}
if ch == 0 {
out[idx] = byte(s)
out[idx+1] = byte(s >> 8)
out[idx] = sum
} else {
out[idx+2] = byte(s)
out[idx+3] = byte(s >> 8)
out[idx+1] = sum
}
}
}

View file

@ -19,7 +19,7 @@ import (
"fmt"
"io"
"github.com/hajimehoshi/go-mp3/internal/consts"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/consts"
)
// A mepg1FrameHeader is MPEG1 Layer 1-3 frame header
@ -122,8 +122,8 @@ func (f FrameHeader) LowSamplingFrequency() int {
return 1
}
func (f FrameHeader) BytesPerFrame() int {
return consts.SamplesPerGr * f.Granules() * 4
func (f FrameHeader) SamplesPerFrame() int {
return consts.SamplesPerGr * f.Granules() * 2
}
func (f FrameHeader) Granules() int {

View file

@ -17,7 +17,7 @@ package huffman
import (
"fmt"
"github.com/hajimehoshi/go-mp3/internal/bits"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/bits"
)
var huffmanTable = []uint16{

View file

@ -17,11 +17,11 @@ package maindata
import (
"fmt"
"github.com/hajimehoshi/go-mp3/internal/bits"
"github.com/hajimehoshi/go-mp3/internal/consts"
"github.com/hajimehoshi/go-mp3/internal/frameheader"
"github.com/hajimehoshi/go-mp3/internal/huffman"
"github.com/hajimehoshi/go-mp3/internal/sideinfo"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/bits"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/consts"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/frameheader"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/huffman"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/sideinfo"
)
func readHuffman(m *bits.Bits, header frameheader.FrameHeader, sideInfo *sideinfo.SideInfo, mainData *MainData, part_2_start, gr, ch int) error {

View file

@ -18,10 +18,10 @@ import (
"fmt"
"io"
"github.com/hajimehoshi/go-mp3/internal/bits"
"github.com/hajimehoshi/go-mp3/internal/consts"
"github.com/hajimehoshi/go-mp3/internal/frameheader"
"github.com/hajimehoshi/go-mp3/internal/sideinfo"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/bits"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/consts"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/frameheader"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/sideinfo"
)
type FullReader interface {

View file

@ -18,9 +18,9 @@ import (
"fmt"
"io"
"github.com/hajimehoshi/go-mp3/internal/bits"
"github.com/hajimehoshi/go-mp3/internal/consts"
"github.com/hajimehoshi/go-mp3/internal/frameheader"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/bits"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/consts"
"git.gammaspectra.live/S.O.N.G/go-mp3/internal/frameheader"
)
type FullReader interface {

0
testdata/classic.mp3 vendored Normal file
View file

0
testdata/mpeg2.mp3 vendored Normal file
View file