Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing sine wave for unknown time

Whole day I was looking for some tutorial or piece of code, "just" to play simple sin wave for "infinity" time. I know it sounds a little crazy.

But I want to be able to change frequency of tone in time, for instance - increase it. Imagine that I want to play tone A, and increase it to C in "+5" frequency steps each 3ms (it's really just example), don't want to have free places, stop the tone.

Is it possible? Or can you help me?

like image 598
eCorke Avatar asked Mar 07 '12 01:03

eCorke


1 Answers

Use NAudio library for audio output.

Make notes wave provider:

class NotesWaveProvider : WaveProvider32
{
    public NotesWaveProvider(Queue<Note> notes)
    {
        this.Notes = notes;
    }
    public readonly Queue<Note> Notes;
    int sample = 0;

    Note NextNote()
    {
        for (; ; )
        {
            if (Notes.Count == 0)
                return null;
            var note = Notes.Peek();
            if (sample < note.Duration.TotalSeconds * WaveFormat.SampleRate)
                return note;

            Notes.Dequeue();
            sample = 0;
        }

    }
    public override int Read(float[] buffer, int offset, int sampleCount)
    {
        int sampleRate = WaveFormat.SampleRate;
        for (int n = 0; n < sampleCount; n++)
        {
            var note = NextNote();
            if (note == null)
                buffer[n + offset] = 0;
            else
                buffer[n + offset] = (float)(note.Amplitude * Math.Sin((2 * Math.PI * sample * note.Frequency) / sampleRate));
            sample++;
        }
        return sampleCount;
    }
}
class Note
{
    public float Frequency;
    public float Amplitude = 1.0f;
    public TimeSpan Duration = TimeSpan.FromMilliseconds(50);

}

start play:

WaveOut waveOut;
this.Notes = new Queue<Note>(new[] { new Note { Frequency = 1000 }, new Note { Frequency = 1100 } });
var waveProvider = new NotesWaveProvider(Notes);
waveProvider.SetWaveFormat(16000, 1); // 16kHz mono    

waveOut = new WaveOut();
waveOut.Init(waveProvider);
waveOut.Play();

add new notes:

void Timer_Tick(...)
{
 if (Notes.Count < 10)
   Notes.Add(new Note{Frecuency = 900});
}

ps this code is idea only. for real using add mt-locking etc

like image 60
Serj-Tm Avatar answered Sep 16 '22 18:09

Serj-Tm