Reputation: 3915
If you have a lisp, please dont try and say my title.
But yes, whats the easiest way to generate simple, or Bonus for more complex sawtooth and other waves.
Upvotes: 4
Views: 2785
Reputation: 17527
There is a Charles Petzold article Simple Electronic Music Sequencer for Silverlight based on Gilles Khouzam's blog entry Playing back Wave files in Silverlight and Pete Brown's Creating Sound using MediaStreamSource in Silverlight 3 Beta. Mike Hodnick has a useful blog post with sample code based on the Petzold article called Digital Audio Synthesis on Windows Phone 7.
In the XAML of the main window Mike introduces a media element
<MediaElement x:Name="media"/>
and then uses the SetSource
method to set the media elements source to the wave he's constructing
this.media.SetSource(new TonesSource());
this.media.Play();
Mike's ToneSource
subclasses his BaseSource
which in turn subclasses MediaStreamSource
and overrides several of its methods: OpenMediaAsync
, GetSampleAsync
, SeekAsync
, CloseMedia
, GetDiagnosticAsync
, and SwitchMediaStreamAsync
. There's more about them in the MSDN documentation; Mike's code itself isn't long but involves bit shifting and writing to memory streams and is worth looking at in the source provided in Mike's blog post.
Mike's ToneSource
class then provides stereo samples
protected override StereoSample GetSample()
{
short left = 0;
short right = 0;
foreach (var oscillator in this.leftOscillators)
left += oscillator.GetNextSample();
foreach (var oscillator in this.rightOscillators)
right += oscillator.GetNextSample();
return new StereoSample() { Left = left, Right = right };
}
using his Oscillator
class
public short GetNextSample()
{
ushort wholePhaseAngle = (ushort)(phaseAngle >> 16);
short amplitude = 0;
amplitude = (short)(short.MaxValue * Math.Sin(2 * Math.PI * wholePhaseAngle / ushort.MaxValue));
amplitude = (short)((amplitude * multiplier) >> 16);
phaseAngle += phaseAngleIncrement;
return amplitude;
}
The NoiseSource
Mike also provides is even simpler than his ToneSource
protected override StereoSample GetSample()
{
return new StereoSample()
{
Left = (short)random.Next(short.MinValue, short.MaxValue),
Right = (short)random.Next(short.MinValue, short.MaxValue)
};
}
Upvotes: 0
Reputation: 49482
Have a look at this question for sample code on how to generate a sine wave in C#. Extending that to square or sawtooth waves would be pretty easy. You can generate more complex waveforms by mixing together simple ones.
You can also use the NAudio WaveFileWriter
class to write the generated data into a WAV file if you require.
Upvotes: 1
Reputation: 74654
Just to elaborate on what Jon already said - all you do is create an 8-bit (i.e. byte[1024]) or 16-bit buffer and fill it out (i.e. for a square wave it's [255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 0]).
Upvotes: 1
Reputation: 1500085
In my experience the .wav file format (the Wikipedia entry lists other documents giving the file format; use whichever you find best) is the simplest widely-used one. It's pretty easy to write uncompressed PCM.
For things like sine waves and sawtooths, I'd split the task into sampling and file production. So you might have an interface such as:
public interface IWave
{
double Sample(double time);
}
where Sample
will be given a time greater than 0 (but possibly greater than 1) and should return a value between -1 and 1. (You could use a delegate for this instead.) Then write a file generator to create a wav file based on the sample duration (e.g. "100000 waves") and sample frequency (e.g. 50000 Hz).
Then it's just a case of implementing IWave
appropriately - e.g. a version which returns sin(time / (2 * pi))
for a simple sine wave, or (time % 1.0) * 2 - 1
for a sawtooth. For bonus amusement, you could write composition functions to speed up or slow down the wave, amplify it, combine other waves etc. The file generator wouldn't need to know any of that, of course. It would just need to take a single IWave
and sample it the appropriate number of times, scaling the [-1, 1] range to [0, 255] appropriately.
Upvotes: 4