<commit_before>// Copyright (c) 2010 AFP Authors

package alsa

import (
  "fmt"
  "unsafe"
  "afp"
  "os"
)

// #include <alsa/asoundlib.h>
import "C"

/////
// Alsa Source
// Listens to a microphone
type AlsaSource struct {
    ctx *afp.Context
    header afp.StreamHeader
    capture *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t
}

func NewAlsaSource() afp.Filter {
    return &AlsaSource{}
}

func (self *AlsaSource) GetType() int {
    return afp.PIPE_SOURCE
}

func (self *AlsaSource) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSource) Start() {

    self.header = afp.StreamHeader {
        Version: 1,
        Channels: 1,
        SampleSize: 32,
        SampleRate: 44100,
        FrameSize: 4096,
    }

    self.ctx.HeaderSink <- self.header

    retval := self.prepare()
    if ( retval != nil) {
        panic(retval)
    }

    for {
		cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
		buff := make([][]float32, self.header.FrameSize)
        length := len(cbuf)

        //first off, grab some data from alsa
        read := C.snd_pcm_readi(self.capture, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
        if read < C.snd_pcm_sframes_t(length) {
            errno := C.snd_pcm_recover(self.capture, C.int(read), 0)
            if errno < 0 {
                panic(fmt.Sprint( "While reading from ALSA device, failed to recover from error: ", errno))
            }
        }

        // snd_pcm_readi gives us a one dimensional array of interleaved data
        // but what we want is a two dimensional array of samples
        chans := int(self.header.Channels)
		for slice, i := 0, 0; i < length; slice, i = slice + 1, i + chans {
			buff[slice] = make([]float32, chans)
			buff[slice] = cbuf[i : i + chans]
        }

        //send it on down the line
        self.ctx.Sink <- buff
    }

}

func (self *AlsaSource) Stop() os.Error {
    C.snd_pcm_close(self.capture)
    close(self.ctx.Sink)
    return nil
}

/////
// Alsa Sink
// Outputs to speakers via ALSA
type AlsaSink struct {
    ctx *afp.Context
    header afp.StreamHeader
    playback *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t

}

func NewAlsaSink() afp.Filter {
    return &AlsaSink{}
}

func (self *AlsaSink) GetType() int {
    return afp.PIPE_SINK
}

func (self *AlsaSink) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSink) Start() {

    const FRAMES int = 256 //the double buffer holds 256 frames
    self.header = <-self.ctx.HeaderSource

    retval := self.prepare()
    if (retval != nil) {
        panic(retval)
    }

    //almost a do..while
    var cbuf []float32 //C buffer
    var written chan C.snd_pcm_sframes_t = make(chan C.snd_pcm_sframes_t)
    chans := int(self.header.Channels)
    double := make([][]float32, 0, self.header.FrameSize * 1024)
    double = append(double, <-self.ctx.Source...)
    length := len(double)
    oldLength := length
    written <- C.snd_pcm_sframes_t(length)

    for buffer := range self.ctx.Source { //blocking

        select {

        //wait for the previous write to finish
        case error := <-written:

            if int(error) < oldLength {
                //not all the data was written to the device
                panic(fmt.Sprintf("Could not write all data to ALSA device, wrote: ", written))
            }

            //write to the speaker in another thread
            go func() {
                oldLength = length
                written <- C.snd_pcm_writei(self.playback, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
            }()

            double = buffer

        default:
            double = append(buffer, <-self.ctx.Source...)
            length = len(double)

            //cbuf WILL be a new pointer, so we can gaurantee that the address space given to snd_pcm_writei
            //will not be modified once it is passed; but on the down side, we rely on the garbage collector
            //to take care of many stale slices created while filling our buffer
            cbuf = make([]float32, int32(self.header.Channels) * self.header.FrameSize * int32(length))

            //interleave the channels
            streamOffset := 0
            for i := 0; i < length; i++ {
                for j := 0; j < chans; j++ {
                    cbuf[streamOffset] = double[i][j]
                    streamOffset++
                }
            }<commit_msg>I had left out a few things from the 'do' in my 'loop'<commit_after>// Copyright (c) 2010 AFP Authors

package alsa

import (
  "fmt"
  "unsafe"
  "afp"
  "os"
)

// #include <alsa/asoundlib.h>
import "C"

/////
// Alsa Source
// Listens to a microphone
type AlsaSource struct {
    ctx *afp.Context
    header afp.StreamHeader
    capture *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t
}

func NewAlsaSource() afp.Filter {
    return &AlsaSource{}
}

func (self *AlsaSource) GetType() int {
    return afp.PIPE_SOURCE
}

func (self *AlsaSource) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func (self *AlsaSource) Start() {

    self.header = afp.StreamHeader {
        Version: 1,
        Channels: 1,
        SampleSize: 32,
        SampleRate: 44100,
        FrameSize: 4096,
    }

    self.ctx.HeaderSink <- self.header

    retval := self.prepare()
    if ( retval != nil) {
        panic(retval)
    }

    for {
		cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
		buff := make([][]float32, self.header.FrameSize)
        length := len(cbuf)

        //first off, grab some data from alsa
        read := C.snd_pcm_readi(self.capture, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
        if read < C.snd_pcm_sframes_t(length) {
            errno := C.snd_pcm_recover(self.capture, C.int(read), 0)
            if errno < 0 {
                panic(fmt.Sprint( "While reading from ALSA device, failed to recover from error: ", errno))
            }
        }

        // snd_pcm_readi gives us a one dimensional array of interleaved data
        // but what we want is a two dimensional array of samples
        chans := int(self.header.Channels)
		for slice, i := 0, 0; i < length; slice, i = slice + 1, i + chans {
			buff[slice] = make([]float32, chans)
			buff[slice] = cbuf[i : i + chans]
        }

        //send it on down the line
        self.ctx.Sink <- buff
    }

}

func (self *AlsaSource) Stop() os.Error {
    C.snd_pcm_close(self.capture)
    close(self.ctx.Sink)
    return nil
}

/////
// Alsa Sink
// Outputs to speakers via ALSA
type AlsaSink struct {
    ctx *afp.Context
    header afp.StreamHeader
    playback *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t

}

func NewAlsaSink() afp.Filter {
    return &AlsaSink{}
}

func (self *AlsaSink) GetType() int {
    return afp.PIPE_SINK
}

func (self *AlsaSink) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    return nil
}

func(self *AlsaSink) Start() {

    const FRAMES int = 256 //the double buffer holds 256 frames
    self.header = <-self.ctx.HeaderSource

    retval := self.prepare()
    if (retval != nil) {
        panic(retval)
    }

    //almost a do..while
    var cbuf []float32 //C buffer
    var written chan C.snd_pcm_sframes_t = make(chan C.snd_pcm_sframes_t, 2)
    chans := int(self.header.Channels)
    double := make([][]float32, 0, self.header.FrameSize * 1024)
    double = append(double, <-self.ctx.Source...)
    length := len(double)
    oldLength := length
    cbuf = make([]float32, int32(self.header.Channels) * self.header.FrameSize * int32(length))
    streamOffset := 0
    for i := 0; i < length; i++ {
        for j := 0; j < chans; j++ {
            cbuf[streamOffset] = double[i][j]
            streamOffset++
        }
    }
    written <- C.snd_pcm_sframes_t(length)

    for buffer := range self.ctx.Source { //blocking

        select {

        //wait for the previous write to finish
        case error := <-written:

            //fmt.Printf(".")

            if int(error) < oldLength {
                //not all the data was written to the device
                panic(fmt.Sprintf("Could not write all data to ALSA device, wrote: ", written))
            }

            //write to the speaker in another thread
            go func() {
                oldLength = length
                written <- C.snd_pcm_writei(self.playback, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
            }()

            double = buffer

        default:

            //fmt.Print("-")
            double = append(double, buffer...)
            length = len(double)

            //cbuf WILL be a new pointer, so we can gaurantee that the address space given to snd_pcm_writei
            //will not be modified once it is passed; but on the down side, we rely on the garbage collector
            //to take care of many stale slices created while filling our buffer
            cbuf = make([]float32, int32(self.header.Channels) * self.header.FrameSize * int32(length))

            //interleave the channels
            streamOffset = 0
            for i := 0; i < length; i++ {
                for j := 0; j < chans; j++ {
                    cbuf[streamOffset] = double[i][j]
                    streamOffset++
                }
            }
{'fraction_non_alphanumeric': 0.11727603164421638, 'fraction_numerical': 0.013042548642292068, 'mean_word_length': 2.080342443200527, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4078713', 'n_tokens_mistral': 3160, 'n_tokens_neox': 2964, 'n_words': 862}