pcm, audio: style changes

This commit is contained in:
Trek H 2019-06-17 13:29:01 +09:30
parent 01561e363d
commit fb12a2f69e
2 changed files with 25 additions and 38 deletions

View File

@ -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.

View File

@ -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
} }