diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml new file mode 100644 index 0000000..71b45ef --- /dev/null +++ b/.github/workflows/releaser.yml @@ -0,0 +1,34 @@ +name: Release Go binaries + +on: + release: + types: [created] + +jobs: + releases-matrix: + name: Release Go Binary + runs-on: ubuntu-latest + strategy: + matrix: + # build and publish in parallel: linux/386, linux/amd64, linux/arm64, windows/386, windows/amd64, darwin/amd64, darwin/arm64 + goos: [linux, windows, darwin] + goarch: ["386", amd64, arm64] + exclude: + - goarch: "386" + goos: darwin + - goarch: arm64 + goos: windows + steps: + - uses: actions/checkout@v2 + - name: Run tests + run: go test -v -p=1 -timeout=0 ./... + - uses: wangyoucao577/go-release-action@v1.35 + with: + project_path: "./cmd/sopro" + github_token: ${{ secrets.GITHUB_TOKEN }} + goos: ${{ matrix.goos }} + goarch: ${{ matrix.goarch }} + binary_name: "sopro" + # ldflags: "-s -w" + extra_files: LICENSE README.md .version AUTHORS + compress_assets: false diff --git a/README.md b/README.md index ca18c6c..6013f3b 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,13 @@ Examples: Plugins: - Connectivity to python neural network inference api with grpc/http and caching the inference +## Example (WIP) + +Trascoding a file from ulaw to wav pcm with CLI + +[![asciicast](https://asciinema.org/a/IXy7MLb1qyXDCCU7IUsrdVkmA.svg)](https://asciinema.org/a/IXy7MLb1qyXDCCU7IUsrdVkmA) + + ## Installation ```bash diff --git a/cmd/sopro/main.go b/cmd/sopro/main.go new file mode 100644 index 0000000..1c89be3 --- /dev/null +++ b/cmd/sopro/main.go @@ -0,0 +1,267 @@ +package main + +import ( + "fmt" + "log" + "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/transcoder" + "github.com/urfave/cli/v2" +) + +const VERSION = "v0.1.3" + +func main() { + + app := &cli.App{ + Name: "sopro", + Usage: "High performance audio processing tool", + Version: VERSION, + Commands: []*cli.Command{ + { + Name: "transcoder", + Usage: "Transcode audio files", + Flags: []cli.Flag{ + + &cli.IntFlag{ + Name: "method", + Usage: "transcode method", + Category: "method", + Required: true, + Value: 1, + }, + + &cli.IntFlag{ + Name: "buffer", + Usage: "buffer size", + Category: "method", + Required: false, + Value: 1024, + }, + + &cli.StringFlag{ + Name: "in", + Usage: "input filename, can be any", + Category: "input", + Required: true, + }, + + &cli.StringFlag{ + Name: "out", + Usage: "output filename, can be any", + Required: true, + }, + + &cli.StringFlag{ + Name: "in-format", + Usage: "input file format", + Category: "input", + // Required: true, + }, + + &cli.StringFlag{ + Name: "out-format", + Usage: "output file format", + Category: "output", + // Required: true, + }, + + &cli.IntFlag{ + Name: "in-sr", + Usage: "input sample rate", + Required: true, + }, + + &cli.IntFlag{ + Name: "out-sr", + Usage: "output sample rate", + Required: true, + }, + + &cli.IntFlag{ + Name: "in-c", + Usage: "input channels", + Required: true, + }, + + &cli.IntFlag{ + Name: "out-c", + Usage: "output channels", + Required: true, + }, + + &cli.IntFlag{ + Name: "in-b", + Usage: "input bits", + Required: true, + }, + + &cli.IntFlag{ + Name: "out-b", + Usage: "output bits", + Required: true, + }, + + &cli.BoolFlag{ + Name: "v", + Usage: "verbose", + Value: false, + Required: false, + }, + }, + + Action: func(ctx *cli.Context) error { + + fmt.Println("[Version] ", ctx.App.Version) + + methodT := ctx.Int("method") + buffer := ctx.Int("buffer") + inputFilename := ctx.String("in") + outputFilename := ctx.String("out") + // inputFormat := ctx.String("in-format") + // outputFormat := ctx.String("out-format") + inputSampleRate := ctx.Int("in-sr") + outputSampleRate := ctx.Int("out-sr") + inputChannels := ctx.Int("in-c") + outputChannels := ctx.Int("out-c") + inputBits := ctx.Int("in-b") + outputBits := ctx.Int("out-b") + verbose := ctx.Bool("v") + + // check required flags + if methodT == -1 { + return cli.Exit("method is required", 1) + } + + if buffer <= 1 { + return cli.Exit("buffer is not valid", 1) + } + + if inputFilename == "" { + return cli.Exit("input file is required", 1) + } + + if outputFilename == "" { + return cli.Exit("output file is required", 1) + } + + // if inputFormat == "" { + // return cli.Exit("input format is required", 1) + // } + + // if outputFormat == "" { + // return cli.Exit("output format is required", 1) + // } + + if inputSampleRate == 0 { + return cli.Exit("input sample rate is required", 1) + } + + if outputSampleRate == 0 { + return cli.Exit("output sample rate is required", 1) + } + + if inputChannels == 0 { + return cli.Exit("input channels is required", 1) + } + + if outputChannels == 0 { + return cli.Exit("output channels is required", 1) + } + + if inputBits == 0 { + return cli.Exit("input bits is required", 1) + } + + if outputBits == 0 { + return cli.Exit("output bits is required", 1) + } + + // print the flags + fmt.Println("[Method] ", methodT) + fmt.Println("[Buffer] ", buffer) + fmt.Println("[Input] ", inputFilename) + fmt.Println("[Output] ", outputFilename) + // fmt.Println("[In Format] ", inputFormat) + // fmt.Println("[Out Format] ", outputFormat) + fmt.Println("[In SR] ", inputSampleRate) + fmt.Println("[Out SR] ", outputSampleRate) + fmt.Println("[In C] ", inputChannels) + fmt.Println("[Out C] ", outputChannels) + fmt.Println("[In B] ", inputBits) + fmt.Println("[Out B] ", outputBits) + fmt.Println("[Verbose] ", verbose) + + // Open the input file + in, err := os.Open(inputFilename) + if err != nil { + panic(err) + } + defer in.Close() + + // Create the output file + out, err := os.Create(outputFilename) + if err != nil { + panic(err) + } + defer out.Close() + + // create a transcoder + t := &transcoder.Transcoder{ + MethodT: methodT, // method.BIT_LOOKUP_TABLE=1 + SourceConfigs: transcoder.TranscoderAudioConfig{ + Endianness: cpuarch.LITTLE_ENDIAN, + }, + TargetConfigs: transcoder.TranscoderAudioConfig{ + Endianness: cpuarch.LITTLE_ENDIAN, + }, + SizeBuffer: buffer, + Verbose: verbose, + } + + // Transcode the file + err = t.Mulaw2Wav( + &transcoder.AudioFileIn{ + Data: in, + AudioFileGeneral: transcoder.AudioFileGeneral{ + Format: fileformat.AUDIO_MULAW, + Config: audioconfig.MulawConfig{ + BitDepth: inputBits, + Channels: inputChannels, + Encoding: encoding.SPACE_LOGARITHMIC, // ulaw is logarithmic + SampleRate: inputSampleRate, + }, + }, + }, + &transcoder.AudioFileOut{ + Data: out, + AudioFileGeneral: transcoder.AudioFileGeneral{ + Format: fileformat.AUDIO_WAV, + Config: audioconfig.WavConfig{ + BitDepth: outputBits, + Channels: outputChannels, + Encoding: encoding.SPACE_LOGARITHMIC, + SampleRate: outputSampleRate, + }, + }, + }, + ) + + if err != nil { + panic(err) + } + + return nil + }, + }, + }, + } + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} diff --git a/go.mod b/go.mod index ddeb554..86cbc6f 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,14 @@ go 1.19 require ( github.com/guptarohit/asciigraph v0.5.5 github.com/olekukonko/tablewriter v0.0.5 + github.com/urfave/cli/v2 v2.24.1 golang.org/x/term v0.4.0 ) require ( + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/sys v0.4.0 // indirect ) diff --git a/go.sum b/go.sum index f9df023..e724e15 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,17 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/guptarohit/asciigraph v0.5.5 h1:ccFnUF8xYIOUPPY3tmdvRyHqmn1MYI9iv1pLKX+/ZkQ= github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU= +github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=