public static void TerminateAudioSampleNode(this DSPGraph graph, DSPNode node)
 {
     using (var block = graph.CreateCommandBlock())
     {
         block.TerminateAudioSampleNode(node);
     }
 }
Пример #2
0
        void Start()
        {
            var format   = ChannelEnumConverter.GetSoundFormatFromSpeakerMode(AudioSettings.speakerMode);
            var channels = ChannelEnumConverter.GetChannelCountFromSoundFormat(format);

            AudioSettings.GetDSPBufferSize(out var bufferLength, out var numBuffers);
            var sampleRate = AudioSettings.outputSampleRate;

            m_Graph = DSPGraph.Create(format, channels, bufferLength, sampleRate);

            var driver = new DefaultDSPGraphDriver {
                Graph = m_Graph
            };

            driver.AttachToDefaultOutput();

            using (var block = m_Graph.CreateCommandBlock())
            {
                m_NoiseFilter = block.CreateDSPNode <NoiseFilter.Parameters, NoiseFilter.Providers, NoiseFilter>();
                block.AddOutletPort(m_NoiseFilter, 2);

                m_LowPass = StateVariableFilter.Create(block, StateVariableFilter.FilterType.Lowpass);

                block.Connect(m_NoiseFilter, 0, m_LowPass, 0);
                block.Connect(m_LowPass, 0, m_Graph.RootDSP, 0);
            }
        }
    void Start()
    {
        var format = ChannelEnumConverter.GetSoundFormatFromSpeakerMode(AudioSettings.speakerMode);
        var channels = ChannelEnumConverter.GetChannelCountFromSoundFormat(format);
        AudioSettings.GetDSPBufferSize(out var bufferLength, out var numBuffers);
        var sampleRate = AudioSettings.outputSampleRate;

        m_Graph = DSPGraph.Create(format, channels, bufferLength, sampleRate);

        var driver = new DefaultDSPGraphDriver { Graph = m_Graph };
        driver.AttachToDefaultOutput();

        using (var block = m_Graph.CreateCommandBlock())
        {
            m_SineWave = block.CreateDSPNode<SinWaveNode.Parameters, SinWaveNode.Providers, SinWaveNode>();
            block.AddOutletPort(m_SineWave, 2, SoundFormat.Stereo);
            m_SawWave = block.CreateDSPNode<SawWaveNode.Parameters, SawWaveNode.Providers, SawWaveNode>();
            block.AddOutletPort(m_SawWave, 2, SoundFormat.Stereo);

            m_MixNode = block.CreateDSPNode<MixNode.Parameters, MixNode.Providers, MixNode>();
            block.AddInletPort(m_MixNode, 2, SoundFormat.Stereo);
            block.AddInletPort(m_MixNode, 2, SoundFormat.Stereo);
            block.AddOutletPort(m_MixNode, 2, SoundFormat.Stereo);

            block.Connect(m_SineWave, 0, m_MixNode, 0);
            block.Connect(m_SawWave, 0, m_MixNode, 1);
            block.Connect(m_MixNode, 0, m_Graph.RootDSP, 0);
        }
    }
Пример #4
0
    public void ReleasingNode_InvalidatesHandle()
    {
        DSPNode node = default;

        using (var setup = new GraphSetup((graphSetup, graph, block) =>
        {
            node = graphSetup.CreateDSPNode <NoParameters, NoProviders, LifecycleTracking>();
            block.AddOutletPort(node, kChannelCount, kSoundFormat);
            block.Connect(node, 0, graph.RootDSP, 0);
            graphSetup.CleanupNodes = false;
        }))
        {
            // Ensure that node is created
            setup.PumpGraph();
            Assert.True(node.Valid);

            // Release node
            using (var block = setup.Graph.CreateCommandBlock())
                block.ReleaseDSPNode(node);
            setup.PumpGraph();

            // Ensure that node handle is no longer valid
            Assert.False(node.Valid);
        }
    }
    public unsafe void InterpolatesEmptyRange()
    {
        DSPNode node = default;

        using (var setup = new GraphSetup((graphSetup, graph, block) =>
        {
            node = graphSetup.CreateDSPNode <SingleParameterKernel.Parameters, NoProviders, SingleParameterKernel>();
        }))
        {
            setup.PumpGraph();

            long   dspClock = 0;
            float4 value    = 10.0f;

            // Get copy of node with populated fields
            node = setup.Graph.LookupNode(node.Handle);
            var nodeParameters = node.Parameters;
            var parameter      = nodeParameters[(int)SingleParameterKernel.Parameters.Parameter];
            var newKeyIndex    = setup.Graph.AppendKey(parameter.KeyIndex, DSPParameterKey.NullIndex, dspClock, value);

            for (int sampleOffset = 0; sampleOffset < 10; ++sampleOffset)
            {
                Assert.AreEqual(value[0], DSPParameterInterpolator.Generate(sampleOffset, setup.Graph.ParameterKeys.UnsafeDataPointer, newKeyIndex, dspClock, float.MinValue, float.MaxValue, value)[0], 0.001f);
            }
        }
    }
 public void EventWithIntHandler(DSPNode evNode, EventWithInt ev)
 {
     Debug.Log("EventWithIntHandler");
     Assert.That(evNode, Is.EqualTo(Node));
     Assert.That(ev.Value, Is.EqualTo(42));
     ++EventWithIntCallCount;
 }
Пример #7
0
    SpectrumRenderer SpawnSpectrumRenderer(DSPNode spectrumNode)
    {
        GameObject       go       = Instantiate(SpectrumRendererPrefab);
        SpectrumRenderer spectrum = go.GetComponent <SpectrumRenderer>();

        spectrum.Init(_Graph, spectrumNode);
        return(spectrum);
    }
 public void EnumEventHandler(DSPNode evNode, EnumEvent ev)
 {
     Debug.Log("EnumEventHandler");
     Assert.That(evNode, Is.EqualTo(Node));
     Assert.That(ev, Is.EqualTo(EnumEvent.EnumEvent1));
     ++EnumEventCallCount;
     Debug.Log("EnumEventHandler call count: " + EnumEventCallCount);
 }
Пример #9
0
    ScopeRenderer SpawnScopeRenderer(DSPNode scopeNode)
    {
        GameObject    go    = Instantiate(ScopeRendererPrefab);
        ScopeRenderer scope = go.GetComponent <ScopeRenderer>();

        scope.Init(_Graph, scopeNode);
        return(scope);
    }
 public void EventWithManyFieldsHandler(DSPNode evNode, EventWithManyFields ev)
 {
     Debug.Log("EventWithManyFieldsHandler");
     Assert.That(evNode, Is.EqualTo(Node));
     Assert.That(ev.IntValue, Is.EqualTo(42));
     Assert.That(ev.BoolValue, Is.EqualTo(true));
     Assert.That(ev.FloatValue, Is.EqualTo(3.1416F));
     Assert.That(ev.CharValue, Is.EqualTo('x'));
     ++EventWithManyFieldsCallCount;
 }
Пример #11
0
    public DSPNode CreateDSPNode <TParameters, TProviders, TAudioKernel>()
        where TParameters   : unmanaged, Enum
        where TProviders    : unmanaged, Enum
        where TAudioKernel  : struct, IAudioKernel <TParameters, TProviders>
    {
        DSPNode node = Block.CreateDSPNode <TParameters, TProviders, TAudioKernel>();

        m_CreatedNodes.Add(node);
        return(node);
    }
 public static void TriggerAudioSample(
     this DSPCommandBlock block,
     DSPNode node,
     AudioSampleDataReader reader,
     Categories category = Categories.OneShot)
 {
     // Kick off playback. This will be done in a better way in the future.
     block.UpdateAudioKernel <StartPlayingAudioSample, Parameters, Providers, PlayAudioSampleReaderNode>(
         new StartPlayingAudioSample(reader, category),
         node
         );
 }
Пример #13
0
 public void AllocatingKernel_Works()
 {
     using (var setup = new GraphSetup((graphSetup, graph, block) =>
     {
         DSPNode node = graphSetup.CreateDSPNode <NoParameters, NoProviders, AllocatingKernel>();
         block.AddOutletPort(node, kChannelCount, kSoundFormat);
         block.Connect(node, 0, graph.RootDSP, 0);
     }))
     {
         setup.PumpGraph();
     }
 }
Пример #14
0
 public void LeakyKernel_EmitsWarning()
 {
     using (var setup = new GraphSetup((graphSetup, graph, block) =>
     {
         DSPNode node = graphSetup.CreateDSPNode <NoParameters, NoProviders, LeakyKernel>();
         block.AddOutletPort(node, kChannelCount, kSoundFormat);
         block.Connect(node, 0, graph.RootDSP, 0);
     }))
     {
         setup.PumpGraph();
         LogAssert.Expect(LogType.Warning, "1 leaked DSP node allocations");
     }
 }
Пример #15
0
    public void Init(DSPGraph graph, DSPNode scopeNode)
    {
        _Graph       = graph;
        _ScopeNode   = scopeNode;
        _Initialized = true;

        var sm = FindObjectOfType <ScopeManager>();

        if (sm != null)
        {
            sm.Register(this);
        }
    }
        public static NodeData CreateGeneratorNode(DSPCommandBlock block, DSPNode consumer, int channelCount, SoundFormat soundFormat)
        {
            var node = block.CreateDSPNode <NoParameters, NoProviders, GenerateOne>();

            block.AddOutletPort(node, channelCount, soundFormat);
            var connection = block.Connect(node, 0, consumer, 0);

            return(new NodeData
            {
                Node = node,
                Connection = connection
            });
        }
    public void DSPNode_WithNoInputsOrOutputs_IsNotExecuted(DSPGraph.ExecutionMode executionMode)
    {
        DSPNode node = default;

        using (var setup = new GraphSetup((graphSetup, graph, block) =>
        {
            node = graphSetup.CreateDSPNode <NoParameters, NoProviders, LifecycleTracking>();
        }))
        {
            setup.PumpGraph();
            Assert.AreEqual(0, LifecycleTracking.Executed);
        }
    }
Пример #18
0
 public void LeakyGraph_DoesntCrash()
 {
     using (var setup = new GraphSetup((graphSetup, graph, block) =>
     {
         DSPNode node = graphSetup.CreateDSPNode <NoParameters, NoProviders, LifecycleTracking>();
         block.AddOutletPort(node, kChannelCount, kSoundFormat);
         block.Connect(node, 0, graph.RootDSP, 0);
     }))
     {
         setup.CleanupNodes = false;
         LogAssert.Expect(LogType.Warning, kNodeLeakMessage);
         setup.PumpGraph();
     }
 }
    static int CountOutputConnections(DSPGraph graph, DSPNode node)
    {
        var connections           = graph.Connections;
        int count                 = 0;
        var outputConnectionIndex = node.OutputConnectionIndex;

        while (outputConnectionIndex != DSPConnection.InvalidIndex)
        {
            ++count;
            outputConnectionIndex = connections[outputConnectionIndex].NextOutputConnectionIndex;
        }

        return(count);
    }
Пример #20
0
 public void StateChange_InvokesLifecycleCallbacks()
 {
     using (var setup = new GraphSetup((graphSetup, graph, block) =>
     {
         DSPNode node = graphSetup.CreateDSPNode <NoParameters, NoProviders, LifecycleTracking>();
         block.AddOutletPort(node, kChannelCount, kSoundFormat);
         block.Connect(node, 0, graph.RootDSP, 0);
     }))
     {
         setup.PumpGraph();
         Assert.Greater(LifecycleTracking.Initialized, 0);
         Assert.Greater(LifecycleTracking.Executed, 0);
         Assert.AreEqual(LifecycleTracking.LifecyclePhase.Executing, LifecycleTracking.Phase);
     }
     Assert.AreEqual(LifecycleTracking.LifecyclePhase.Disposed, LifecycleTracking.Phase);
 }
Пример #21
0
    public void AllocatingKernelMemory_DuringUpdateJob_Works()
    {
        var node = new DSPNode();

        using (var setup = new GraphSetup((graphSetup, graph, block) =>
        {
            node = graphSetup.CreateDSPNode <NoParameters, NoProviders, LifecycleTracking>();
            block.AddOutletPort(node, kChannelCount, kSoundFormat);
            block.Connect(node, 0, graph.RootDSP, 0);
        }))
        {
            using (var block = setup.Graph.CreateCommandBlock())
                block.CreateUpdateRequest <AllocatingUpdateJob, NoParameters, NoProviders, LifecycleTracking>(new AllocatingUpdateJob(), node, null);
            setup.PumpGraph();
        }
    }
    public void ReleasingDSPNode_InChain_KillsSignal(DSPGraph.ExecutionMode executionMode)
    {
        DSPNode generator   = default;
        DSPNode passthrough = default;

        using (var setup = new GraphSetup((graphSetup, graph, block) =>
        {
            generator = block.CreateDSPNode <NoParameters, NoProviders, GenerateOne>();
            block.AddOutletPort(generator, GraphSetup.ChannelCount, GraphSetup.SoundFormat);

            passthrough = block.CreateDSPNode <NoParameters, NoProviders, PassThrough>();
            block.AddInletPort(passthrough, GraphSetup.ChannelCount, GraphSetup.SoundFormat);
            block.AddOutletPort(passthrough, GraphSetup.ChannelCount, GraphSetup.SoundFormat);

            block.Connect(generator, 0, passthrough, 0);
            block.Connect(passthrough, 0, graph.RootDSP, 0);
        }))
        {
            using (var buffer = new NativeArray <float>(setup.Graph.DSPBufferSize * GraphSetup.ChannelCount, Allocator.Temp))
            {
                setup.Graph.BeginMix(setup.Graph.DSPBufferSize);
                setup.Graph.ReadMix(buffer, setup.Graph.DSPBufferSize, GraphSetup.ChannelCount);
                foreach (var sample in buffer)
                {
                    Assert.AreEqual(1.0f, sample, 0.001f);
                }

                using (var block = setup.Graph.CreateCommandBlock())
                    block.ReleaseDSPNode(passthrough);

                setup.Graph.BeginMix(setup.Graph.DSPBufferSize);
                setup.Graph.ReadMix(buffer, setup.Graph.DSPBufferSize, GraphSetup.ChannelCount);
                foreach (var sample in buffer)
                {
                    Assert.AreEqual(0.0f, sample, 0.001f);
                }

                using (var block = setup.Graph.CreateCommandBlock())
                    block.ReleaseDSPNode(generator);
            }
        }
    }
 public void MixOverwritesData(DSPGraph.ExecutionMode executionMode)
 {
     using (var setup = new GraphSetup((graphSetup, graph, block) =>
     {
         DSPNode node = graphSetup.CreateDSPNode <NoParameters, NoProviders, GenerateOne>();
         block.AddOutletPort(node, GraphSetup.ChannelCount, GraphSetup.SoundFormat);
         block.Connect(node, 0, graph.RootDSP, 0);
     }))
     {
         using (var buffer = new NativeArray <float>(setup.Graph.DSPBufferSize * GraphSetup.ChannelCount, Allocator.Temp, NativeArrayOptions.ClearMemory))
         {
             setup.Graph.BeginMix(setup.Graph.DSPBufferSize, executionMode);
             setup.Graph.ReadMix(buffer, setup.Graph.DSPBufferSize, GraphSetup.ChannelCount);
             foreach (var sample in buffer)
             {
                 Assert.AreEqual(1.0f, sample, 0.001f);
             }
         }
     }
 }
Пример #24
0
        private void ReleaseNode(DSPNode node, AudioSampleNodeCompleted @event)
        {
            if (@event.category != Categories.OneShot ||
                !this._available.IsCreated)
            {
                return;
            }

            using (var block = this._graph.CreateCommandBlock())
            {
                block.Disconnect(
                    node,
                    0,
                    this._graph.RootDSP,
                    0
                    );
            }

            this._available.Enqueue(node);
        }
    void Start()
    {
        var format   = ChannelEnumConverter.GetSoundFormatFromSpeakerMode(AudioSettings.speakerMode);
        var channels = ChannelEnumConverter.GetChannelCountFromSoundFormat(format);

        AudioSettings.GetDSPBufferSize(out var bufferLength, out var numBuffers);

        var sampleRate = AudioSettings.outputSampleRate;

        m_Graph = DSPGraph.Create(format, channels, bufferLength, sampleRate);

        var driver = new DefaultDSPGraphDriver {
            Graph = m_Graph
        };

        m_Output = driver.AttachToDefaultOutput();

        // Add an event handler delegate to the graph for ClipStopped. So we are notified
        // of when a clip is stopped in the node and can handle the resources on the main thread.
        m_HandlerID = m_Graph.AddNodeEventHandler <ClipStopped>((node, evt) =>
        {
            Debug.Log("Received ClipStopped event on main thread, cleaning resources");
        });

        // All async interaction with the graph must be done through a DSPCommandBlock.
        // Create it here and complete it once all commands are added.
        var block = m_Graph.CreateCommandBlock();

        m_Node = block.CreateDSPNode <PlayClipNode.Parameters, PlayClipNode.SampleProviders, PlayClipNode>();

        // Currently input and output ports are dynamic and added via this API to a node.
        // This will change to a static definition of nodes in the future.
        block.AddOutletPort(m_Node, 2, SoundFormat.Stereo);

        // Connect the node to the root of the graph.
        m_Connection = block.Connect(m_Node, 0, m_Graph.RootDSP, 0);

        // We are done, fire off the command block atomically to the mixer thread.
        block.Complete();
    }
Пример #26
0
    public void WritingToInputBuffer_Throws(DSPGraph.ExecutionMode executionMode)
    {
        using (var setup = new GraphSetup((graphSetup, graph, block) =>
        {
            DSPNode generator = graphSetup.CreateDSPNode <NoParameters, NoProviders, GenerateOne>();
            block.AddOutletPort(generator, kChannelCount, kSoundFormat);

            DSPNode node = graphSetup.CreateDSPNode <NoParameters, NoProviders, WritingToInputBufferKernel>();
            block.AddInletPort(node, kChannelCount, kSoundFormat);
            block.AddOutletPort(node, kChannelCount, kSoundFormat);

            block.Connect(generator, 0, node, 0);
            block.Connect(node, 0, graph.RootDSP, 0);
        }))
        {
            using (var buff = new NativeArray <float>(200, Allocator.TempJob))
            {
                setup.Graph.BeginMix(0, executionMode);
                setup.Graph.ReadMix(buff, 200 / kChannelCount, kChannelCount);
            }
        }
    }
Пример #27
0
    void AddProviderToNode <TKernel>(DSPCommandBlock block, DSPNode node, int index = -1, float value = kSignalValueA, Providers item = Providers.VariableSizeArray, bool insert = true)
        where TKernel : struct, IAudioKernel <NoParameters, Providers>
    {
        var provider = AudioSampleProvider.Create(kChannelCount, kSampleRate);

        provider.enableSilencePadding = false;
        var inputBuff = new NativeArray <float>(2 * kChannelCount * kDspBufferSize, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

        for (int i = 0; i < inputBuff.Length; ++i)
        {
            inputBuff[i] = value;
        }
        provider.QueueSampleFrames(inputBuff);
        inputBuff.Dispose();
        if (insert)
        {
            block.InsertSampleProvider <NoParameters, Providers, TKernel>(provider.id, node, item, index);
        }
        else
        {
            block.SetSampleProvider <NoParameters, Providers, TKernel>(provider.id, node, item, index);
        }
    }
Пример #28
0
    void ConfigureDSP()
    {
        AudioConfiguration audioConfig = AudioSettings.GetConfiguration();

        Debug.LogFormat("BufferSize={0} SampleRate={1}", audioConfig.dspBufferSize, audioConfig.sampleRate);
        _MicrophoneClip = Microphone.Start(Microphone.devices[0], true, 1, audioConfig.sampleRate);
        Debug.LogFormat("Microphone Channels={0} Frequency={1} Samples={2} Ambisonic={3}", _MicrophoneClip.channels, _MicrophoneClip.frequency, _MicrophoneClip.samples, _MicrophoneClip.ambisonic);
        _MicrophoneBuffer    = new NativeArray <float>(_MicrophoneClip.samples, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
        _MicrophoneDataArray = new float[_MicrophoneClip.samples];

        _Graph  = DSPGraph.Create(SoundFormat.Stereo, 2, audioConfig.dspBufferSize, audioConfig.sampleRate);
        _Driver = new MyAudioDriver {
            Graph = _Graph
        };
        _OutputHandle = _Driver.AttachToDefaultOutput();

        // create graph structure
        using (var block = _Graph.CreateCommandBlock())
        {
            //
            // create nodes
            //
            _Microphone = block.CreateDSPNode <MicrophoneNode.Parameters, MicrophoneNode.Providers, MicrophoneNode>();
            block.AddOutletPort(_Microphone, 1, SoundFormat.Mono);

            _Scope = block.CreateDSPNode <ScopeNode.Parameters, ScopeNode.Providers, ScopeNode>();
            block.AddInletPort(_Scope, 1, SoundFormat.Mono);

            _Spectrum = block.CreateDSPNode <SpectrumNode.Parameters, SpectrumNode.Providers, SpectrumNode>();
            block.AddInletPort(_Spectrum, 1, SoundFormat.Mono);

            _MonoToStereo = block.CreateDSPNode <MonoToStereoNode.Parameters, MonoToStereoNode.Providers, MonoToStereoNode>();
            block.AddInletPort(_MonoToStereo, 1, SoundFormat.Mono); // left
            block.AddInletPort(_MonoToStereo, 1, SoundFormat.Mono); // right
            block.AddOutletPort(_MonoToStereo, 2, SoundFormat.Stereo);

            //
            // connect nodes
            //
            block.Connect(_Microphone, 0, _MonoToStereo, 0);
            block.Connect(_Microphone, 0, _MonoToStereo, 1);

            block.Connect(_MonoToStereo, 0, _Graph.RootDSP, 0);

            block.Connect(_Microphone, 0, _Scope, 0);
            block.Connect(_Microphone, 0, _Spectrum, 0);

            //
            // set parameters
            //
            block.SetFloat <ScopeNode.Parameters, ScopeNode.Providers, ScopeNode>(_Scope, ScopeNode.Parameters.Time, 1f);
            block.SetFloat <ScopeNode.Parameters, ScopeNode.Providers, ScopeNode>(_Scope, ScopeNode.Parameters.TriggerTreshold, 0f);

            block.SetFloat <SpectrumNode.Parameters, SpectrumNode.Providers, SpectrumNode>(_Spectrum, SpectrumNode.Parameters.Window, (float)SpectrumNode.WindowType.Hamming);
        }

        _ScopeRenderer        = SpawnScopeRenderer(_Scope);
        _ScopeRenderer.Height = 5.0f;
        _ScopeRenderer.Offset = 0.0f;

        _SpectrumRenderer = SpawnSpectrumRenderer(_Spectrum);

        StartCoroutine(InitMicCoroutine());
    }
 public NodeData CreateGeneratorNode(DSPNode consumer, int channelCount = DefaultChannelCount, SoundFormat soundFormat = DefaultSoundFormat)
 {
     using (var block = Graph.CreateCommandBlock())
         return(CreateGeneratorNode(block, consumer, channelCount, soundFormat));
 }
 public static void TerminateAudioSampleNode(this DSPCommandBlock block, DSPNode node)
 {
     block.UpdateAudioKernel <TerminateAudioSampleNode, Parameters, Providers, PlayAudioSampleReaderNode>(
         new TerminateAudioSampleNode(),
         node);
 }