2016-10-31 5 views
2

Я написал небольшое приложение, которое записывает данные со звуковой карты и сохраняет данные в массиве для последующей обработки.Функция добавления перезаписывает существующие данные в срезе

Когда новые данные доступны, portaudio выполняет обратный вызов record. В обратном вызове я добавляю данные в массив RecData.data.

golang встроенная функция append добавляет, как ожидается, еще один элемент к срезу, , но по какой-либо причине также перезаписывает все существующие элементы в массиве с точно такими же данными.

Я пытался изолировать проблему более двух дней без успеха.

Вот усеченную версию кода, который работает и показывает проблему:

package main 

import (
    "fmt" 
    "time" 
// "reflect" 

    "github.com/gordonklaus/portaudio" 
) 

type RecData struct{ 
    data [][][]float32 
} 

func main() { 

    var inputChs int = 1 
    var outputChs int = 0 
    var samplingRate float64 = 48000 
    var framesPerBuffer int = 3 //for test purpose that low. Would normally be 1024 or 2048 

    rec := RecData{make([][][]float32, 0, 1000)} 

    portaudio.Initialize() 

    stream, err := portaudio.OpenDefaultStream(inputChs, outputChs, samplingRate, framesPerBuffer, rec.record) 
    if err != nil { 
     fmt.Println(err) 
    } 

    defer stream.Close() 
    stream.Start() 
    for { 
     time.Sleep(time.Millisecond * 10) 
    } 
} 

// callback which gets called when new data is in the buffer 
func (re *RecData)record(in [][]float32) { 
    fmt.Println("Received sound sample: ") 
    fmt.Println(in) 
    re.data = append(re.data, in) 
    fmt.Println("Content of RecData.data after adding received sound sample:") 
    fmt.Println(re.data, "\n") 
    time.Sleep(time.Millisecond * 500) //limit temporarily the amount of data read 
    // iterate over all recorded data and compare them 
    /* 
    for i, d := range re.data{ 
     if reflect.DeepEqual(d, in){ 
       fmt.Printf("Data at index %d is the same as the recorded one, but should not be!\n", i) 
     } 
    }*/ 
} 

2. Обновление

Это выход приложения:

Received sound sample: 
[[0.71575254 1.0734825 0.7444282]] 
Content of RecData.data after adding received sound sample: 
[[[0.71575254 1.0734825 0.7444282]]] 

Received sound sample: 
[[0.7555193 0.768355 0.6575008]] 
Content of RecData.data after adding received sound sample: 
[[[0.7555193 0.768355 0.6575008]] [[0.7555193 0.768355 0.6575008]]] 

Received sound sample: 
[[0.7247052 0.68471473 0.6843796]] 
Content of RecData.data after adding received sound sample: 
[[[0.7247052 0.68471473 0.6843796]] [[0.7247052 0.68471473 0.6843796]] [[0.7247052 0.68471473 0.6843796]]] 

Received sound sample: 
[[0.6996536 0.66283375 0.67252487]] 
Content of RecData.data after adding received sound sample: 
[[[0.6996536 0.66283375 0.67252487]] [[0.6996536 0.66283375 0.67252487]] [[0.6996536 0.66283375 0.67252487]] [[0.6996536 0.66283375 0.67252487]]] 


.... etc .... 

Как мы видим, со временем размер среза растет, но вместо того, чтобы просто добавлять данные, данные в массиве также переписываются эн.

Этого не должно быть. portaudio предоставляет в обратном вызове [][]float32 с образцом звука, записанным со звуковой карты. Как вы можете видеть, они всегда разные.

Как уже упоминалось, приведенный выше код является урезанной версией моего приложения. Обычно я записывал, скажем, 5 секунд, а затем выполнял бы быстрое преобразование Фурье (FFT) над образцами для вычисления спектра. Я оставил эту часть, так как она не влияет на эту конкретную проблему.

Я был бы очень признателен за любую помощь. Может быть, кто-нибудь может указать мне, что я делаю неправильно.

Спасибо!

+0

'append' никогда не переписывает существующие данные в том же массиве. «append» может потребоваться выделить новый массив, если срез не имеет достаточной емкости, что, конечно же, требует _copying_ данных для нового массива поддержки. Это то, о чем вы говорите? – JimB

+0

Нет, данные будут явно перезаписаны. Также я понимаю, что append не перезаписывает данные, но я все еще сталкиваюсь с проблемой, что после вызова append в обратном вызове существующие данные в массиве перезаписываются :-( – DH1TW

+0

Возможно, у вас может быть какая-то параллельная процедура которые делают этот беспорядок. –

ответ

4

Буфер, переданный в обратный вызов, повторно используется пакетом portaudio, поэтому вы добавляете одну и ту же структуру среза к своему фрагменту data. Каждый раз, когда буфер, выделенный portaudio, перезаписывает данные, вы видите результаты в каждом элементе вашего ломтика data.

Вам нужно будет выделять новые кусочки и сделать копию данных:

func (re *RecData) record(in [][]float32) { 
    buf := make([][]float32, len(in)) 
    for i, v := range in { 
     buf[i] = append([]float32(nil), v...) 
    } 
    re.data = append(re.data, buf) 

Пример: https://play.golang.org/p/cF57lQIZFU

+0

получил! Спасибо за фрагмент кода @JimB! Я подтверждаю, теперь данные правильно добавляются в 'RecData.data'! В очередной раз благодарим за помощь! – DH1TW

+0

Вместо добавления к 'buf' каждый раз, я бы сделал' buf' соответствующий размер в первую очередь. Таким образом, для 'buf' произойдет только одно распределение. –

+0

На самом деле я поменю его на 'make' в этом примере, но не совсем по этой причине (обычно я просто рекомендую, чтобы люди не беспокоились об этом и использовали' append', так как он хорошо амортизируется и оставляет более чистый код). Учитывая данные примера, распределение номеров будет одинаковым, за исключением того, что мы будем перераспределять память, поскольку по умолчанию 'append' from 0 выделяет емкость 2. – JimB

 Смежные вопросы

  • Нет связанных вопросов^_^