Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions examples/localization.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func main() {
file, err := os.OpenFile("M1F1-Alaw-AFsp.wav", os.O_RDWR, 066)
file, err := os.OpenFile("guns/gun_war-2-stereo.wav", os.O_RDWR, 066)
if err != nil {
fmt.Println(err)
}
Expand All @@ -19,7 +19,7 @@ func main() {
fmt.Println(err)
}

f, err := os.Create("M1F1-Alaw-AFsp_localized.wav")
f, err := os.Create("15_left_gun_war-2.wav")
defer f.Close()
if err != nil {
fmt.Println(err)
Expand All @@ -30,39 +30,55 @@ func main() {
agraph.SampleRate(int(reader.Fmt.Data.SampleRate)),
agraph.BitsPerSample(int(reader.Fmt.Data.BitsPerSample)))

localizationNode, _ := agraph.NewNode(agraph.LocalizationFilter,
localizationNode, err := agraph.NewNode(agraph.LocalizationFilter,
"localization",
agraph.Angle(0))
agraph.Angle(15))

if err != nil {
panic(err)
}

localizationNode.SetSink(make(chan []uint16, 0))

go localizationNode.Process()
start := time.Now()

i := 0
var originalFirstSample uint16
for {
//fmt.Printf("i: %v\n", i)
if i == 1885 {
fmt.Printf("Original First Sample: %v\n", originalFirstSample)
//panic("PAUSE")
}

data, err := reader.ReadSampleInt16()
if err != nil {
fmt.Println(err)
break
}

if i == 0 {
originalFirstSample = data[0]
}


localizationNode.Source() <- data
modifiedData := <-localizationNode.Sink()
//fmt.Printf("Localized: %v\n", modifiedData)


leftByte := make([]byte, 2)
rightByte := make([]byte, 2)
binary.LittleEndian.PutUint16(leftByte, modifiedData[0])
binary.LittleEndian.PutUint16(rightByte, modifiedData[1])

/*

/*
fmt.Print("Packet Info: \n")
fmt.Printf(" - Original [%v]uint16 = %v \n", len(data), data)
// fmt.Printf(" - Modified [%v]uint16 = %v \n", len(data), data)
fmt.Printf(" - Modified [%v]uint16 = %v \n", len(modifiedData), modifiedData)
fmt.Printf(" - L: [%v]byte = %v \n - R: [%v]byte = %v \n", len(leftByte), leftByte, len(rightByte), rightByte)
*/
*/

// pack all the bytes into the correct ordering
fullByte := make([]byte, 4)
Expand All @@ -76,8 +92,8 @@ func main() {


// fmt.Println()

writer.Write(fullByte)
i++
}

writer.Close()
Expand Down
59 changes: 56 additions & 3 deletions localization_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"time"
"math"
"strconv"
"container/list"
"fmt"
"strings"
)

/*
Expand All @@ -27,12 +30,13 @@ import (
x x
x x
x x
180°/-180°
-180°/180°
*/

const (
R = 9 // radius of the head in cm
C = 345 // speed of sound in m/s
sampleRate = 22050 // won't work with audio that isn't 8000 (won't give the proper delay length)
)

type Localization struct {
Expand All @@ -41,19 +45,40 @@ type Localization struct {
Name string
Angle float64
itd time.Duration
sampleDelay int
delayChannel int
delayBuf *list.List
}

func newLocalization(name string, angle float64) (Node, error) {
itd, err := itd(angle, R, C)
if err != nil {
return nil, err
}

delayChannel := 0

if angle > 0 {
delayChannel = 1
}

// number of samples to buffer
sampleDelay := int(math.Floor(itd.Seconds() * sampleRate))

fmt.Printf("sample delay info: \n" +
" - itd seconds: %v \n" +
" - sampleRate: %v \n" +
" - sample delay %v \n", itd.Seconds(), sampleRate, sampleDelay)

return &Localization{
source: make(chan []uint16, SOURCE_SIZE),
sink: nil,
Name: name,
Angle: angle,
itd: itd,
sampleDelay: sampleDelay,
delayChannel: delayChannel,
delayBuf: list.New(),
}, nil
}

Expand Down Expand Up @@ -85,19 +110,47 @@ func (n *Localization) Process() error {
}

func (n *Localization) do(data []uint16) ([]uint16, error) {
// add samples to the buffer if it isn't full
if n.delayBuf.Len() < n.sampleDelay {
n.delayBuf.PushFront(data[n.delayChannel])
}
//fmt.Println(n.sampleDelay)
//fmt.Printf("LENGH OF DELAY BUF: %v\n", n.delayBuf.Len())

// if the buffer is full, replace the sample with the value
if n.delayBuf.Len() == n.sampleDelay {
samp := n.delayBuf.Back().Value.(uint16)
//fmt.Printf("Reading from buffer! \n - samp uint16: %v \n", samp)
n.delayBuf.Remove(n.delayBuf.Back())
data[n.delayChannel] = samp
} else {
// otherwise, set that sample in the data stream to 0
data[n.delayChannel] = 0
}

return data, nil
}

// interaural time difference (ITD)
// ∆t = r/c(θ + sin(θ))
// angle is in degrees coming in
func itd(angle float64, radius float64, c float64) (time.Duration, error) {

angRad := angle * 0.0174533

// calculate the itd
itd := (radius / c) * (angle + math.Sin(angle))
itd := math.Abs((radius / c) * (angRad + math.Sin(angle)))

// prepare the itd to be parsed as a duration
itdStrConv := strconv.FormatFloat(itd, 'f', -1, 64)
fmt.Println(itdStrConv)
unitIdent := "s"
itdStrArr := []string{itdStrConv, unitIdent}


itdStr := strings.Join(itdStrArr, "")

// duration
return time.ParseDuration(itdStrConv)
return time.ParseDuration(itdStr)
}