using Godot; using System.Reflection; using System.Collections.Generic; using System.Text; namespace Rokojori { [GlobalClass] public partial class SineWaveTest: Node { [Export] public float frequency = 100; [Export] public AudioStreamPlayer player; AudioStreamGeneratorPlayback _playback; public override void _Ready() { CreateGraph(); if ( player.Stream is AudioStreamGenerator generator ) { ag.sampleRate = generator.MixRate; player.Play(); _playback = (AudioStreamGeneratorPlayback) ( player.GetStreamPlayback() ); Fill(); } } WaveTableGenerator generator; AudioGraph ag; Constant constant; public override void _Process( double delta ) { Fill(); } void Fill() { if ( _playback == null ) { return; } constant.SetConstant( frequency ); int framesAvailable = _playback.GetFramesAvailable(); if ( framesAvailable == 0 ) { return; } int blocks = 0; while ( framesAvailable > frameBuffer.Count ) { ProcessAudio(); blocks ++; } var frameBufferData = frameBuffer.ToArray(); var bufferSlice = new Vector2[ framesAvailable ]; System.Array.Copy( frameBufferData, 0, bufferSlice, 0, framesAvailable ); _playback.PushBuffer( bufferSlice ); var rest = new Vector2[ frameBuffer.Count - framesAvailable ]; System.Array.Copy( frameBufferData, framesAvailable, rest, 0, rest.Length ); frameBuffer = new List( rest ); } List frameBuffer = new List(); void ProcessAudio() { ag.Process(); var outputBuffer = generator.output.GetOutputStreamBuffer(); var data = new Vector2[ ag.bufferSize ]; for ( int i = 0; i < ag.bufferSize ; i++ ) { data[ i ] = outputBuffer[ i ] * Vector2.One; } frameBuffer.AddRange( data ); } public void CreateGraph() { ag = new AudioGraph(); var sine = new float[ 2048 ]; var square = new float[ 2048 ]; for ( int i = 0; i < sine.Length; i++ ) { var p = i / 2048f; var v = Mathf.Sin( p * Mathf.Pi * 2.0f ); sine[ i ] = v; square[ i ] = i < sine.Length / 2 ? 1 : -1; } var sines = new Vector2[ 10 ]; sines[ 0 ] = Vector2.Zero; for ( int i = 1; i < sines.Length; i++ ) { sines[ i ] = new Vector2( Mathf.Pow( 0.5f, i - 1 ), 0 ); } var waveTable = WaveTable.FromSines( sines ); waveTable.Normalize(); generator = new WaveTableGenerator( ag, waveTable ); constant = new Constant( ag, frequency ); constant.output.ConnectTo( generator.frequency ); ag.output = generator; } } }