diff --git a/examples/record/main.go b/examples/record/main.go index bd3cae4..bfb8248 100644 --- a/examples/record/main.go +++ b/examples/record/main.go @@ -23,7 +23,7 @@ func main() { } defer microphone.Terminate() - stream, format, err := microphone.OpenDefaultStream(44100) + stream, format, err := microphone.OpenDefaultStream(44100, 2) if err != nil { log.Fatal(err) } diff --git a/go.mod b/go.mod index 772a656..7689055 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/MarkKremer/microphone go 1.12 require ( - github.com/faiface/beep v1.0.1 + github.com/faiface/beep v1.0.2 github.com/gordonklaus/portaudio v0.0.0-20180817120803-00e7307ccd93 github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.3.0 diff --git a/go.sum b/go.sum index cb753c5..1244bde 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/faiface/beep v1.0.1 h1:SYTt7Bpt0C9KgeLkyNzTTuW9o3D3lTyAPAwCr5EQjO4= github.com/faiface/beep v1.0.1/go.mod h1:1yLb5yRdHMsovYYWVqYLioXkVuziCSITW1oarTeduQM= +github.com/faiface/beep v1.0.2 h1:UB5DiRNmA4erfUYnHbgU4UB6DlBOrsdEFRtcc8sCkdQ= +github.com/faiface/beep v1.0.2/go.mod h1:1yLb5yRdHMsovYYWVqYLioXkVuziCSITW1oarTeduQM= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.1.1/go.mod h1:K1udHkiR3cOtlpKG5tZPD5XxrF7v2y7lDq7Whcj+xkQ= github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= diff --git a/microphone.go b/microphone.go index ab65e30..29e9b4d 100644 --- a/microphone.go +++ b/microphone.go @@ -3,10 +3,15 @@ package microphone import ( + "errors" "github.com/faiface/beep" "github.com/gordonklaus/portaudio" ) +var ( + invalidAmountOfInputChannelsError = errors.New("invalid amount of inputChannels specified. microphone.OpenDefaultStream func expects exactly 2 or 1") +) + // Init initializes internal datastructures of PortAudio and // the host APIs for use. // @@ -38,12 +43,19 @@ func Terminate() error { const bufferSize = 512 // OpenDefaultStream opens the default input stream. -func OpenDefaultStream(sampleRate beep.SampleRate) (s *Streamer, format beep.Format, err error) { +func OpenDefaultStream(sampleRate beep.SampleRate, inputChannels int) (s *Streamer, format beep.Format, err error) { + if inputChannels > 2 || inputChannels == 0 { + return nil, beep.Format{}, invalidAmountOfInputChannelsError + } + s = &Streamer{} - s.buffer = make([][]float32, 2) - s.buffer[0] = make([]float32, bufferSize) - s.buffer[1] = make([]float32, bufferSize) - s.stream, err = portaudio.OpenDefaultStream(2, 0, float64(sampleRate), bufferSize, s.buffer) + s.buffer = make([][]float32, inputChannels) + + for i := range s.buffer { + s.buffer[i] = make([]float32, bufferSize) + } + + s.stream, err = portaudio.OpenDefaultStream(inputChannels, 0, float64(sampleRate), bufferSize, s.buffer) if err != nil { return nil, beep.Format{}, err } @@ -52,7 +64,7 @@ func OpenDefaultStream(sampleRate beep.SampleRate) (s *Streamer, format beep.For s.pos = bufferSize format = beep.Format{ SampleRate: sampleRate, - NumChannels: 2, + NumChannels: inputChannels, // NOTE(m): I couldn't find how to obtain the actual precision // from the microphone. 3 bytes is the highest precision // supported by the beep library for saving WAV files. @@ -106,8 +118,7 @@ func (s *Streamer) Stream(samples [][2]float64) (int, bool) { var i int for i = 0; i < n; i++ { - samples[i][0] = float64(s.buffer[0][s.pos+i]) - samples[i][1] = float64(s.buffer[1][s.pos+i]) + samples[i] = convertBufferIntoSamples(s.buffer, s.pos+i) } if n == len(samples) { @@ -128,8 +139,7 @@ func (s *Streamer) Stream(samples [][2]float64) (int, bool) { } for i = 0; i < m; i++ { - samples[n+i][0] = float64(s.buffer[0][i]) - samples[n+i][1] = float64(s.buffer[1][i]) + samples[n+i] = convertBufferIntoSamples(s.buffer, i) } n += m @@ -150,3 +160,19 @@ func (s *Streamer) Err() error { func (s *Streamer) Close() error { return s.stream.Close() } + +func convertBufferIntoSamples(buffer [][]float32, bufferPos int) [2]float64 { + var samples [2]float64 + + if len(buffer) > 1 { + samples[0] = float64(buffer[0][bufferPos]) + samples[1] = float64(buffer[1][bufferPos]) + + return samples + } + + samples[0] = float64(buffer[0][bufferPos]) + samples[1] = float64(buffer[0][bufferPos]) + + return samples +} diff --git a/microphone_test.go b/microphone_test.go index 6bd9a10..e1f939f 100644 --- a/microphone_test.go +++ b/microphone_test.go @@ -25,7 +25,7 @@ func ExampleOpenDefaultStream_recordWav() { } defer Terminate() - stream, format, err := OpenDefaultStream(44100) + stream, format, err := OpenDefaultStream(44100, 1) if err != nil { log.Fatal(err) }