Skip to content

Commit

Permalink
Merge pull request #13 from pablodz/dev
Browse files Browse the repository at this point in the history
support lpcm to wav lpcm
  • Loading branch information
pablodz authored Feb 23, 2023
2 parents 6658389 + cbd07f5 commit 727799c
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 0 deletions.
80 changes: 80 additions & 0 deletions examples/lpcm2wav_lpcm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package main

import (
"bytes"
"math"
"os"

"github.com/pablodz/sopro/pkg/audioconfig"
"github.com/pablodz/sopro/pkg/cpuarch"
"github.com/pablodz/sopro/pkg/encoding"
"github.com/pablodz/sopro/pkg/fileformat"
"github.com/pablodz/sopro/pkg/method"
"github.com/pablodz/sopro/pkg/sopro"
"github.com/pablodz/sopro/pkg/transcoder"
)

func main() {

// generate sin wave in slice of bytes
data := []byte{}
for i := 0; i < 10000; i++ {
// sin wave
data = append(data, byte(128+127*math.Sin(2*math.Pi*float64(i)/100)))
}

// Open the input file
in := bytes.NewBuffer(data)

// Create the output file
out, err := os.Create("./internal/samples/output_lpcm.wav")
if err != nil {
panic(err)
}
defer out.Close()

// create a transcoder
t := &transcoder.Transcoder{
MethodT: method.NOT_FILLED,
InConfigs: sopro.AudioConfig{
Endianness: cpuarch.LITTLE_ENDIAN,
},
OutConfigs: sopro.AudioConfig{
Endianness: cpuarch.LITTLE_ENDIAN,
},
SizeBuffer: 1024,
Verbose: true,
}

// Transcode the file
err = t.Pcm2Wav(
&sopro.In{
Data: in,
AudioFileGeneral: sopro.AudioFileGeneral{
Format: fileformat.AUDIO_PCM,
Config: audioconfig.PcmConfig{
BitDepth: 8,
Channels: 1,
Encoding: encoding.SPACE_LINEAR, // ulaw is logarithmic
SampleRate: 8000,
},
},
},
&sopro.Out{
Data: out,
AudioFileGeneral: sopro.AudioFileGeneral{
Format: fileformat.AUDIO_WAV,
Config: audioconfig.WavConfig{
BitDepth: 8,
Channels: 1,
Encoding: encoding.SPACE_LINEAR,
SampleRate: 8000,
},
},
},
)

if err != nil {
panic(err)
}
}
File renamed without changes.
File renamed without changes.
101 changes: 101 additions & 0 deletions pkg/transcoder/lpcm_2_wav-lpcm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package transcoder

import (
"bufio"
"fmt"
"io"
"os"

"github.com/pablodz/sopro/pkg/audioconfig"
"github.com/pablodz/sopro/pkg/cpuarch"
"github.com/pablodz/sopro/pkg/encoding"
"github.com/pablodz/sopro/pkg/sopro"
"github.com/pablodz/sopro/utils"
)

// PCM to WAV-LPCM transcoder is only adding the WAV header to the PCM data
func lpcm2WavLpcm(in *sopro.In, out *sopro.Out, tr *Transcoder) (err error) {
if tr.Verbose {
// read all the file
sopro.GraphIn(in)
}

// Get the WAV file configuration
channels := out.Config.(audioconfig.WavConfig).Channels
sampleRate := out.Config.(audioconfig.WavConfig).SampleRate
bitsPerSample := out.Config.(audioconfig.WavConfig).BitDepth
tr.InConfigs.Encoding = in.Config.(audioconfig.PcmConfig).Encoding
tr.OutConfigs.Encoding = out.Config.(audioconfig.WavConfig).Encoding
tr.BitDepth = bitsPerSample

if tr.InConfigs.Endianness == cpuarch.NOT_FILLED && tr.OutConfigs.Endianness == cpuarch.NOT_FILLED {
tr.InConfigs.Endianness = cpuarch.LITTLE_ENDIAN // replace with cpuarch.GetEndianess()
tr.OutConfigs.Endianness = cpuarch.LITTLE_ENDIAN
}

tr.Println(
"\n[Format] ", in.Format, "=>", out.Format,
"\n[Encoding] ", encoding.ENCODINGS[in.Config.(audioconfig.PcmConfig).Encoding], "=>", encoding.ENCODINGS[out.Config.(audioconfig.WavConfig).Encoding],
"\n[Channels] ", in.Config.(audioconfig.PcmConfig).Channels, "=>", channels,
"\n[SampleRate] ", in.Config.(audioconfig.PcmConfig).SampleRate, "=>", sampleRate, "Hz",
"\n[BitDepth] ", in.Config.(audioconfig.PcmConfig).BitDepth, "=>", bitsPerSample, "bytes",
"\n[Transcoder][Source][Encoding]", encoding.ENCODINGS[tr.InConfigs.Encoding],
"\n[Transcoder][Target][Encoding]", encoding.ENCODINGS[tr.OutConfigs.Encoding],
"\n[Transcoder][BitDepth] ", tr.BitDepth,
"\n[Transcoder][Endianness] ", cpuarch.ENDIANESSES[cpuarch.GetEndianess()],
)

// Create a buffered reader and writer
in.Reader = bufio.NewReader(in.Data)
out.Writer = bufio.NewWriter(out.Data)
out.Length = 0
headerWavZero := utils.GenerateSpaceForWavHeader()

out.Writer.Write(headerWavZero)
out.Length += 44

// Copy the data from the input file to the output file in chunks
if _, err = TranscodeBytes(in, out, tr); err != nil {
return fmt.Errorf("error converting bytes: %v", err)
}
// Flush the output file
err = out.Writer.Flush()
if err != nil {
return fmt.Errorf("error flushing output file: %v", err)
}
tr.Println("Wrote", out.Length, "bytes to output file")

// Update the file size and data size fields
fileFixer := out.Data.(*os.File)
r, err := fileFixer.Seek(0, io.SeekStart)
if err != nil {
return fmt.Errorf("error seeking file: %v", err)
}
tr.Println("Seeked to:", r)

out.NewConfig(audioconfig.WavConfig{
BitDepth: bitsPerSample,
Channels: channels,
Encoding: tr.OutConfigs.Encoding,
SampleRate: sampleRate,
WaveFormat: audioconfig.WAVE_FORMAT_PCM,
})
headersWav := utils.GenerateWavHeadersWithSize(out.Config.(audioconfig.WavConfig), out.Length)

if tr.Verbose {
audioconfig.PrintWavHeaders(headersWav)
}

n, err := fileFixer.Write(headersWav)
if err != nil {
return fmt.Errorf("error writing file size: %v", err)
}
tr.Println("File size:", fmt.Sprintf("% 02x", out.Length-8), "bytes written:", n)
tr.Println("Data size:", fmt.Sprintf("% 02x", out.Length-44), "bytes written:", n)

if tr.Verbose {
sopro.GraphOut(in, out)
}

return fileFixer.Close()
}
21 changes: 21 additions & 0 deletions pkg/transcoder/system_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,24 @@ func (t *Transcoder) Mulaw2Wav(in *sopro.In, out *sopro.Out) error {

}
}

func (t *Transcoder) Pcm2Wav(in *sopro.In, out *sopro.Out) error {
inSpace := in.Config.(audioconfig.PcmConfig).Encoding
outSpace := out.Config.(audioconfig.WavConfig).Encoding

switch {
case t.MethodT == method.NOT_FILLED &&
inSpace == encoding.SPACE_LINEAR &&
outSpace == encoding.SPACE_LINEAR:
return lpcm2WavLpcm(in, out, t)
default:
return fmt.Errorf(
"[%s] %s: %s -> %s",
method.METHODS[t.MethodT],
sopro.ErrUnsupportedTranscoding,
encoding.ENCODINGS[inSpace],
encoding.ENCODINGS[outSpace],
)

}
}

0 comments on commit 727799c

Please sign in to comment.