140 lines
2.8 KiB
C#
140 lines
2.8 KiB
C#
|
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<Vector2>( rest );
|
||
|
}
|
||
|
|
||
|
List<Vector2> frameBuffer = new List<Vector2>();
|
||
|
|
||
|
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;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|