我是否应该避免使用共享变量?

时间:2019-06-13 09:01:02

标签: go audio concurrency channel portaudio

我正在写一个声音合成器。最终项目没有GUI,但现在我正在使用go-astilectron,这样我就可以轻松地测试具有钢琴键盘和所有振荡器设置(ADSR,滤波器,统一,ecc等)的合成器。

要输出我正在使用portaudio(https://github.com/gordonklaus/portaudio)的合成器发出的声音,这是负责它的代码块:

stream, err := portaudio.OpenDefaultStream(0, 1, sampleRate, bufferSize, func(out []float32) {
        for i := 0; i < len(buf); i++ {
            var valLive, valLoop float32
            //If a single note has been set by the GUI
            if note.Samples > 0 {
                valLive = note.GetSample(instrument)
            }
            //If a loop of notes has been set by the GUI
            if len(notes) > 0{
                valLoop = notes.GetSample(instrument)
            }
            buf[i] = valLive + valLoop
        }
        //TODO: sound filters
        for i, val := range buf{
            out[i] = val
        }
    })

OpenDefaultStream的最后一个参数是一个将输出作为写入PCM数据的参数的函数。

我假设portaudio程序包在goroutine中运行了回调,因为一旦我单击GUI的虚拟键盘上的一个键,该程序就不会停止,并且输出的音频将立即生效。 notenotes是我整个main包中可用的全局变量,它们是由GUI发送的astilectron事件设置的,这是接收它们的代码段:

case "play":
    // Unmarshal payload
    if len(m.Payload) > 0 {
        // Unmarshal payload
        if err = json.Unmarshal(m.Payload, &note); err != nil {
            payload = err.Error()
            return
        }
    }

    payload = note
    note.Init(instrument)
case "loop":
    // Unmarshal payload
    if len(m.Payload) > 0 {
        // Unmarshal payload
        if err = json.Unmarshal(m.Payload, &notes); err != nil {
            payload = err.Error()
            return
        }
    }

    payload = notes
    notes.Init(instrument)

有效载荷只是包含所有注释信息(半音,长度)的JSON,note.Init()计算样本数并将其设置为note.Samples,触发portaudio回调获取样本并输出他们。

到目前为止,这段代码已经完美地运行了,从来没有给我带来任何问题,但是有些事情令我担心。基本上,我让portaudio和electronic都访问相同的变量,并且我假设它们都使用goroutine,据我所知这是一个很大的禁忌。我应该改用频道吗?

如果是这样,我正在考虑创建2个全局通道,并使用portaudio回调内部的select提取实时和循环采样。

正如我所说,这段代码可以完美运行,因此在继续实施可能破坏它的渠道之前,我想知道它是否值得。

谢谢大家

0 个答案:

没有答案