mirror of https://bitbucket.org/ausocean/av.git
pcm, audio: style changes
This commit is contained in:
parent
01561e363d
commit
fb12a2f69e
|
@ -41,15 +41,14 @@ import (
|
||||||
// - If the number of bytes in b.Data is not divisible by the decimation factor (ratioFrom), the remaining bytes will
|
// - If the number of bytes in b.Data is not divisible by the decimation factor (ratioFrom), the remaining bytes will
|
||||||
// not be included in the result. Eg. input of length 480002 downsampling 6:1 will result in output length 80000.
|
// not be included in the result. Eg. input of length 480002 downsampling 6:1 will result in output length 80000.
|
||||||
func Resample(b alsa.Buffer, rate int) (alsa.Buffer, error) {
|
func Resample(b alsa.Buffer, rate int) (alsa.Buffer, error) {
|
||||||
var newBuf alsa.Buffer
|
|
||||||
if b.Format.Rate == rate {
|
if b.Format.Rate == rate {
|
||||||
return newBuf, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
if b.Format.Rate < 0 {
|
if b.Format.Rate < 0 {
|
||||||
return newBuf, fmt.Errorf("Unable to convert from: %v Hz", b.Format.Rate)
|
return alsa.Buffer{}, fmt.Errorf("Unable to convert from: %v Hz", b.Format.Rate)
|
||||||
}
|
}
|
||||||
if rate < 0 {
|
if rate < 0 {
|
||||||
return newBuf, fmt.Errorf("Unable to convert to: %v Hz", rate)
|
return alsa.Buffer{}, fmt.Errorf("Unable to convert to: %v Hz", rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of bytes in a sample.
|
// The number of bytes in a sample.
|
||||||
|
@ -60,7 +59,7 @@ func Resample(b alsa.Buffer, rate int) (alsa.Buffer, error) {
|
||||||
case alsa.S16_LE:
|
case alsa.S16_LE:
|
||||||
sampleLen = 2 * b.Format.Channels
|
sampleLen = 2 * b.Format.Channels
|
||||||
default:
|
default:
|
||||||
return newBuf, fmt.Errorf("Unhandled ALSA format: %v", b.Format.SampleFormat)
|
return alsa.Buffer{}, fmt.Errorf("Unhandled ALSA format: %v", b.Format.SampleFormat)
|
||||||
}
|
}
|
||||||
inPcmLen := len(b.Data)
|
inPcmLen := len(b.Data)
|
||||||
|
|
||||||
|
@ -71,7 +70,7 @@ func Resample(b alsa.Buffer, rate int) (alsa.Buffer, error) {
|
||||||
|
|
||||||
// ratioTo = 1 is the only number that will result in an even sampling.
|
// ratioTo = 1 is the only number that will result in an even sampling.
|
||||||
if ratioTo != 1 {
|
if ratioTo != 1 {
|
||||||
return newBuf, fmt.Errorf("unhandled from:to rate ratio %v:%v: 'to' must be 1", ratioFrom, ratioTo)
|
return alsa.Buffer{}, fmt.Errorf("unhandled from:to rate ratio %v:%v: 'to' must be 1", ratioFrom, ratioTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
newLen := inPcmLen / ratioFrom
|
newLen := inPcmLen / ratioFrom
|
||||||
|
@ -100,28 +99,25 @@ func Resample(b alsa.Buffer, rate int) (alsa.Buffer, error) {
|
||||||
resampled = append(resampled, bAvg...)
|
resampled = append(resampled, bAvg...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new alsa.Buffer with resampled data.
|
// Return a new alsa.Buffer with resampled data.
|
||||||
newBuf = alsa.Buffer{
|
return alsa.Buffer{
|
||||||
Format: alsa.BufferFormat{
|
Format: alsa.BufferFormat{
|
||||||
Channels: b.Format.Channels,
|
Channels: b.Format.Channels,
|
||||||
SampleFormat: b.Format.SampleFormat,
|
SampleFormat: b.Format.SampleFormat,
|
||||||
Rate: rate,
|
Rate: rate,
|
||||||
},
|
},
|
||||||
Data: resampled,
|
Data: resampled,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
return newBuf, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StereoToMono returns raw mono audio data generated from only the left channel from
|
// StereoToMono returns raw mono audio data generated from only the left channel from
|
||||||
// the given stereo recording (ALSA buffer)
|
// the given stereo recording (ALSA buffer)
|
||||||
func StereoToMono(b alsa.Buffer) (alsa.Buffer, error) {
|
func StereoToMono(b alsa.Buffer) (alsa.Buffer, error) {
|
||||||
var newBuf alsa.Buffer
|
|
||||||
if b.Format.Channels == 1 {
|
if b.Format.Channels == 1 {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
if b.Format.Channels != 2 {
|
if b.Format.Channels != 2 {
|
||||||
return newBuf, fmt.Errorf("Audio is not stereo or mono, it has %v channels", b.Format.Channels)
|
return alsa.Buffer{}, fmt.Errorf("Audio is not stereo or mono, it has %v channels", b.Format.Channels)
|
||||||
}
|
}
|
||||||
|
|
||||||
var stereoSampleBytes int
|
var stereoSampleBytes int
|
||||||
|
@ -131,7 +127,7 @@ func StereoToMono(b alsa.Buffer) (alsa.Buffer, error) {
|
||||||
case alsa.S16_LE:
|
case alsa.S16_LE:
|
||||||
stereoSampleBytes = 4
|
stereoSampleBytes = 4
|
||||||
default:
|
default:
|
||||||
return newBuf, fmt.Errorf("Unhandled ALSA format %v", b.Format.SampleFormat)
|
return alsa.Buffer{}, fmt.Errorf("Unhandled ALSA format %v", b.Format.SampleFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
recLength := len(b.Data)
|
recLength := len(b.Data)
|
||||||
|
@ -147,17 +143,15 @@ func StereoToMono(b alsa.Buffer) (alsa.Buffer, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new alsa.Buffer with resampled data.
|
// Return a new alsa.Buffer with resampled data.
|
||||||
newBuf = alsa.Buffer{
|
return alsa.Buffer{
|
||||||
Format: alsa.BufferFormat{
|
Format: alsa.BufferFormat{
|
||||||
Channels: 1,
|
Channels: 1,
|
||||||
SampleFormat: b.Format.SampleFormat,
|
SampleFormat: b.Format.SampleFormat,
|
||||||
Rate: b.Format.Rate,
|
Rate: b.Format.Rate,
|
||||||
},
|
},
|
||||||
Data: mono,
|
Data: mono,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
return newBuf, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gcd is used for calculating the greatest common divisor of two positive integers, a and b.
|
// gcd is used for calculating the greatest common divisor of two positive integers, a and b.
|
||||||
|
|
|
@ -43,13 +43,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pkg = "pkg: "
|
pkg = "audio: "
|
||||||
rbTimeout = 100 * time.Millisecond
|
rbTimeout = 100 * time.Millisecond
|
||||||
rbNextTimeout = 100 * time.Millisecond
|
rbNextTimeout = 100 * time.Millisecond
|
||||||
rbLen = 200
|
rbLen = 200
|
||||||
defaultSampleRate = 48000
|
defaultSampleRate = 48000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// "running" means the input goroutine is reading from the ALSA device and writing to the ringbuffer.
|
||||||
|
// "paused" means the input routine is sleeping until unpaused or stopped.
|
||||||
|
// "stopped" means the input routine is stopped and the ALSA device is closed.
|
||||||
const (
|
const (
|
||||||
running = iota
|
running = iota
|
||||||
paused
|
paused
|
||||||
|
@ -59,24 +62,17 @@ const (
|
||||||
// Rates contains the standard audio sample rates used by package audio.
|
// Rates contains the standard audio sample rates used by package audio.
|
||||||
var Rates = [8]int{8000, 16000, 32000, 44100, 48000, 88200, 96000, 192000}
|
var Rates = [8]int{8000, 16000, 32000, 44100, 48000, 88200, 96000, 192000}
|
||||||
|
|
||||||
// Device holds everything we need to know about the audio input stream.
|
// Device holds everything we need to know about the audio input stream and implements io.Reader.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
l Logger
|
l Logger // Logger for device's routines to log to.
|
||||||
|
mode uint8 // Operating mode, either running, paused, or stopped.
|
||||||
// Operating mode, either running, paused, or stopped.
|
mu sync.Mutex // Provides synchronisation when changing modes concurrently.
|
||||||
// "running" means the input goroutine is reading from the ALSA device and writing to the ringbuffer.
|
|
||||||
// "paused" means the input routine is sleeping until unpaused or stopped.
|
|
||||||
// "stopped" means the input routine is stopped and the ALSA device is closed.
|
|
||||||
mode uint8
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
title string // Name of audio title, or empty for the default title.
|
title string // Name of audio title, or empty for the default title.
|
||||||
dev *alsa.Device // Audio input device.
|
dev *alsa.Device // ALSA's Audio input device.
|
||||||
ab alsa.Buffer // ALSA's buffer.
|
ab alsa.Buffer // ALSA's buffer.
|
||||||
rb *ring.Buffer // Our buffer.
|
rb *ring.Buffer // Our buffer.
|
||||||
chunkSize int // This is the number of bytes that will be stored at a time.
|
chunkSize int // This is the number of bytes that will be stored in rb at a time.
|
||||||
|
*Config // Configuration parameters for this device.
|
||||||
*Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config provides parameters used by Device.
|
// Config provides parameters used by Device.
|
||||||
|
@ -155,7 +151,7 @@ func (d *Device) Start() error {
|
||||||
case running:
|
case running:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return errors.New("invalid mode")
|
return fmt.Errorf("invalid mode: %d", mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +181,6 @@ func (d *Device) open() error {
|
||||||
d.l.Log(logger.Debug, pkg+"opening sound card")
|
d.l.Log(logger.Debug, pkg+"opening sound card")
|
||||||
cards, err := alsa.OpenCards()
|
cards, err := alsa.OpenCards()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.l.Log(logger.Debug, pkg+"failed to open sound card")
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer alsa.CloseCards(cards)
|
defer alsa.CloseCards(cards)
|
||||||
|
@ -207,14 +202,12 @@ func (d *Device) open() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d.dev == nil {
|
if d.dev == nil {
|
||||||
d.l.Log(logger.Debug, pkg+"failed to find audio device")
|
|
||||||
return errors.New("no audio device found")
|
return errors.New("no audio device found")
|
||||||
}
|
}
|
||||||
|
|
||||||
d.l.Log(logger.Debug, pkg+"opening audio device", "title", d.dev.Title)
|
d.l.Log(logger.Debug, pkg+"opening audio device", "title", d.dev.Title)
|
||||||
err = d.dev.Open()
|
err = d.dev.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.l.Log(logger.Debug, pkg+"failed to open audio device")
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue