Fading sound in/out - c#

I have a background sound playing in an endless loop. I want it to fade out when the user does press a button.
I tried the following:
A DirectSoundOut is initiated with the WaveStream
A Timer changes the volume of the WaveChannel32.
The Problem:
Changing the volume while the sound is playing produces noises.
Does anyone knows a better solution?

To perform a smooth fade-in or fade-out, you need to do so at the sample level. You then multiply each sample by a gradually increasing or decreasing number. You are using WaveChannel32, so your audio has already been converted to 32 bit float. I would then create another IWaveProvider implementer that was responsible for doing the fade in and fade out. Normally it would pass through samples unchanged, but in the Read method, if you are in a fade in or fade out, it would multiply each sample (or pair if it is stereo).
The ISampleProvider interface in NAudio 1.5 was designed to make this type of thing much easier, as it allows you to deal samples already as 32 bit floats, rather than implementing IWaveProvider which requires you to convert from a byte[] to float[]. Here's a SampleProvider for fade-in and fade-out I just made which I will include in the next NAudio, and hopefully blog about it soon. Just call BeginFadeIn or BeginFadeOut with the appropriate fade duration.
public class FadeInOutSampleProvider : ISampleProvider
{
enum FadeState
{
Silence,
FadingIn,
FullVolume,
FadingOut,
}
private readonly object lockObject = new object();
private readonly ISampleProvider source;
private int fadeSamplePosition;
private int fadeSampleCount;
private FadeState fadeState;
public FadeInOutSampleProvider(ISampleProvider source)
{
this.source = source;
this.fadeState = FadeState.FullVolume;
}
public void BeginFadeIn(double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeState = FadeState.FadingIn;
}
}
public void BeginFadeOut(double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeState = FadeState.FadingOut;
}
}
public int Read(float[] buffer, int offset, int count)
{
int sourceSamplesRead = source.Read(buffer, offset, count);
lock (lockObject)
{
if (fadeState == FadeState.FadingIn)
{
FadeIn(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.FadingOut)
{
FadeOut(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.Silence)
{
ClearBuffer(buffer, offset, count);
}
}
return sourceSamplesRead;
}
private static void ClearBuffer(float[] buffer, int offset, int count)
{
for (int n = 0; n < count; n++)
{
buffer[n + offset] = 0;
}
}
private void FadeOut(float[] buffer, int offset, int sourceSamplesRead)
{
int sample = 0;
while (sample < sourceSamplesRead)
{
float multiplier = 1.0f - (fadeSamplePosition / (float)fadeSampleCount);
for (int ch = 0; ch < source.WaveFormat.Channels; ch++)
{
buffer[offset + sample++] *= multiplier;
}
fadeSamplePosition++;
if (fadeSamplePosition > fadeSampleCount)
{
fadeState = FadeState.Silence;
// clear out the end
ClearBuffer(buffer, sample + offset, sourceSamplesRead - sample);
break;
}
}
}
private void FadeIn(float[] buffer, int offset, int sourceSamplesRead)
{
int sample = 0;
while (sample < sourceSamplesRead)
{
float multiplier = (fadeSamplePosition / (float)fadeSampleCount);
for (int ch = 0; ch < source.WaveFormat.Channels; ch++)
{
buffer[offset + sample++] *= multiplier;
}
fadeSamplePosition++;
if (fadeSamplePosition > fadeSampleCount)
{
fadeState = FadeState.FullVolume;
// no need to multiply any more
break;
}
}
}
public WaveFormat WaveFormat
{
get { return source.WaveFormat; }
}
}

Or you can just, do this:
while (waveOut.volume > 0.1)
{
waveOut.volume -= 0.1;
System.Threading.Thread.Sleep(10);
}
^ An example of a fade-out. I use it in my own programs, works fine.

Related

Xamarin Urho IOS how to set up an application?

I am following this example but it is not that useful:
https://github.com/xamarin/urho-samples/tree/master/FeatureSamples/Core/29_SoundSynthesis
anyhow I am getting an run time error that says: The application is not configured yet.
but I made an application object .
the error happen a node = new Node();
what am I missing
this is my class:
using System;
using Urho.Audio;
using Urho;
using Urho.Resources;
using Urho.Gui;
using System.Diagnostics;
using System.Globalization;
namespace Brain_Entrainment
{
public class IsochronicTones : Urho.Application
{
/// Scene node for the sound component.
Node node;
/// Sound stream that we update.
BufferedSoundStream soundStream;
public double Frequency { get; set; }
public double Beat { get; set; }
public double Amplitude { get; set; }
public float Bufferlength { get; set; }
const int numBuffers = 3;
public IsochronicTones(ApplicationOptions AppOption) : base(AppOption)
{
Amplitude = 1;
Frequency = 100;
Beat = 0;
Bufferlength = Int32.MaxValue;
}
public void play()
{
Start();
}
protected override void OnUpdate(float timeStep)
{
UpdateSound();
base.OnUpdate(timeStep);
}
protected override void Start()
{
base.Start();
CreateSound();
}
void CreateSound()
{
// Sound source needs a node so that it is considered enabled
node = new Node();
SoundSource source = node.CreateComponent();
soundStream = new BufferedSoundStream();
// Set format: 44100 Hz, sixteen bit, mono
soundStream.SetFormat(44100, true, false);
// Start playback. We don't have data in the stream yet, but the
//SoundSource will wait until there is data
// as the stream is by default in the "don't stop at end" mode
source.Play(soundStream);
}
void UpdateSound()
{
// Try to keep 1/10 seconds of sound in the buffer, to avoid both
//dropouts and unnecessary latency
float targetLength = 1.0f / 10.0f;
float requiredLength = targetLength -
Bufferlength;//soundStream.BufferLength;
float w = 0;
if (requiredLength < 0.0f)
return;
uint numSamples = (uint)(soundStream.Frequency * requiredLength);
if (numSamples == 0)
return;
// Allocate a new buffer and fill it with a simple two-oscillator
//algorithm.The sound is over - amplified
// (distorted), clamped to the 16-bit range, and finally lowpass -
//filtered according to the coefficient
var newData = new short[numSamples];
for (int i = 0; i < numSamples; ++i)
{
float newValue = 0;
if (Beat == 0)
{
newValue = (float)(Amplitude * Math.Sin(Math.PI * Frequency * i / 44100D));
}
else
{
w = (float)(1D * Math.Sin(i * Math.PI * Beat / 44100D));
if (w < 0)
{
w = 0;
}
newValue = (float)(Amplitude * Math.Sin(Math.PI * Frequency * i / 44100D));
}
//accumulator = MathHelper.Lerp(accumulator, newValue, filter);
newData[i] = (short)newValue;
}
// Queue buffer to the stream for playback
soundStream.AddData(newData, 0, newData.Length);
}
}
}

naudio WaveOut not playing all data provided by iSampleProvider

I am working on a click generator using nAudio. As a test, I created a ISampleProvidor class to read/play from an audio file. The iSampleProvider reads in a PCM (32-bit ieee) wav file and then plays it back using the WaveOut player. The WaveOut plays only about 1/4 of the audio passed via the IsampleProvidor Read() method. This results in a choppy playback. The ISampleProvider read() method requests the correct amount of data at the correct time intervals, but the WaveOut only plays the first 25% of the samples provided back to the interface. Any Idea how to address this, or am I using the wrong classes to build a click track (the BufferedWaveProvider might also work, but it only buffers 5 seconds of audio)?
public void TestSampleProvider()
{
ISampleProvider mySamples = new MySamples();
var _waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()) {DeviceNumber = 0};
_waveOut.Init(mySamples);
_waveOut.Play();
Console.ReadLine();
}
public class MySamples : ISampleProvider
{
private float[] samplesFloats;
private int position;
private WaveFileReader clicksound;
public int Read(float[] buffer, int offset, int count)
{
var copyCount = count;
if (position + copyCount > samplesFloats.Count())
{
copyCount = samplesFloats.Count() - position;
}
Console.WriteLine("samplesFloats {0} position {1} copyCount {2} offset {3} time {4}", samplesFloats.Count(), position, copyCount, offset, DateTime.Now.Millisecond);
Buffer.BlockCopy(samplesFloats, position, buffer, offset, copyCount);
position += copyCount;
return copyCount;
}
public MySamples()
{
clicksound = new WaveFileReader(#"C:\temp\sample.wav");
WaveFormat = clicksound.WaveFormat;
samplesFloats = new float[clicksound.SampleCount];
for (int i = 0; i < clicksound.SampleCount; i++)
{
samplesFloats[i] = clicksound.ReadNextSampleFrame()[0];//it;s a mono file
}
}
public WaveFormat WaveFormat { get; private set; }
}
I think there may be an issue with the WaveOut using the ISampleProvider, so I used the IWaveProvider interface to do the same thing. In fact, here's a bare bones class for sending a non-ending click to the waveout. This might run into memory issues if you let it run a long time but for pop songs it should be fine. Also this will only work for 32-bit files (note the *4 on the byte buffer)
public class MyClick : IWaveProvider
{
private int position;
private WaveFileReader clicksound;
private byte[] samplebuff;
MemoryStream _byteStream = new System.IO.MemoryStream();
public MyClick(float bpm=120)
{
clicksound = new WaveFileReader(#"click_sample.wav");
var bpmsampleslen = (60 / bpm) * clicksound.WaveFormat.SampleRate;
samplebuff = new byte[(int) bpmsampleslen*4];
clicksound.Read(samplebuff, 0,(int) clicksound.Length);
_byteStream.Write(samplebuff, 0, samplebuff.Length);
_byteStream.Position = 0;
WaveFormat = clicksound.WaveFormat;
}
public int Read(byte[] buffer, int offset, int count)
{
//we reached the end of the stream add another one to the end and keep playing
if (count + _byteStream.Position > _byteStream.Length)
{
var holdpos = _byteStream.Position;
_byteStream.Write(samplebuff, 0, samplebuff.Length);
_byteStream.Position = holdpos;
}
return _byteStream.Read(buffer, offset, count);
}
public WaveFormat WaveFormat { get; private set; }
}

Fibonacci Boxes

I know there's a lot of Fibonacci questions and answers on Stack overflow and the web in general, but this is a problem that's been vexing me for a while now, and i can't seem to crack it or find a solution.
Creating Fibonacci algorithms are easy enough, there's plenty of them, but i'm trying to create the boxes in a spiral formation graphically using C#. This is not for Uni or anything, it's just a problem that i've spent way too much time on that i now need to find a solution for, if you know what i mean?
Here's what i've got so far, now i did have a better configuration, but with countless hours of revising the code, this is what i have at the moment:
public partial class Form1 : Form
{
public const int FIBNUM = 6;
public const int CENTRE = 10;
public const int SIZE = 10;
public const int OFFSET = 100;
public Form1()
{
InitializeComponent();
drawSpiral();
}
private int fib(int n)
{
switch (n)
{
case 0:
return 0;
case 1:
return 1;
default:
return fib(n - 1) + fib(n - 2);
}
}
private void drawSpiral()
{
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
Rectangle r = new Rectangle(0, 0, 0, 0);
int fibnum = 0;
int centre = 0;
int size = 0;
int cnt = 0;
for (int n = 1; n <= FIBNUM; n++)
{
fibnum = fib(n);
centre = fibnum * CENTRE;
size = fibnum * SIZE;
++cnt;
if (cnt == 1)
{
if (n == 1)
{
r = new Rectangle(fibnum + OFFSET, fibnum + OFFSET, size, size);
g.DrawRectangle(Pens.Red, r);
r = new Rectangle((fibnum + size) + OFFSET, fibnum + OFFSET, size, size);
g.DrawRectangle(Pens.Purple, r);
n++;
}
else
{
r = new Rectangle((centre - size) + OFFSET, (centre - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Black, r);
}
continue;
}
if(cnt == 2)
{
r = new Rectangle((fibnum) + OFFSET, (fibnum - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Blue, r);
continue;
}
if (cnt == 3)
{
r = new Rectangle((fibnum - size) + OFFSET, (fibnum - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Green, r);
continue;
}
if (cnt == 4)
{
r = new Rectangle((fibnum - size / 2) + OFFSET, (fibnum - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Gray, r);
}
cnt = 0;
}
}
pictureBox1.Invalidate();
}
I've taken an image from wikipedia of what it is i'm trying to create graphically :
Thanks in advance.
I think your code is too complicated, because you try to do a lot at once. Consider the following code where the spiral is drawn around the origin, without scaling and translating:
// the current fibonacci numbers
int current = 1;
int previous = 0;
// the current bounding box
int left = 0;
int right = 1;
int top = 0;
int bottom = 0;
// the number of boxes you want to draw
const int N = 10;
for (int i = 0; i < N; i++) {
switch (i % 4) {
case 0: // attach to bottom of current rectangle
drawRectangle(g, left, right, bottom, bottom + current);
bottom += current;
break;
case 1: // attach to right of current rectangle
drawRectangle(g, right, right + current, top, bottom);
right += current;
break;
case 2: // attach to top of current rectangle
drawRectangle(g, left, right, top - current, top);
top -= current;
break;
case 3: // attach to left of current rectangle
drawRectangle(g, left - current, left, top, bottom);
left -= current;
break;
}
// update fibonacci number
int temp = current;
current += previous;
previous = temp;
}
You can then deal with the actual drawing part in the separate method drawRectangle (I left out all details about the actual graphics objects, but you can probably do that yourself).
const int SCALE = 5;
const int OFFSET = 150;
private void drawRectangle(Graphics g, int left, int right, int top, int bottom)
{
g.DrawRectangle(Pens.Red, new Rectangle(SCALE * left + OFFSET,
SCALE * top + OFFSET,
SCALE * (right - left),
SCALE * (bottom - top)));
}
Output:
Here you go :
public partial class Form1 : Form
{
public const int FIBNUM = 8;
public const int CENTERX = 300;
public const int CENTERY = 300;
public const int ZOOM = 10;
public Form1()
{
InitializeComponent();
drawSpiral();
}
private int fib(int n, int p = 0, int q = 1)
{
switch (n)
{
case 0: return 0;
case 1: return q;
default: return fib(n - 1, q, p + q);
}
}
private void drawSpiral()
{
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
Rectangle r = new Rectangle(0, 0, 0, 0);
int x = CENTERX;
int y = CENTERY;
for (int n = 1; n <= FIBNUM; n++)
{
int fibnum = fib(n)*ZOOM;
r = new Rectangle(x, y, fibnum, fibnum);
g.DrawRectangle(Pens.Red, r);
switch (n % 4)
{
case 0:
{
y += fibnum;
break;
}
case 1:
{
x += fibnum;
y -= fib(n - 1) * ZOOM;
break;
}
case 2:
{
x -= fib(n - 1)*ZOOM;
y -= fib(n + 1)*ZOOM;
break;
}
case 3:
{
x -= fib(n + 1) * ZOOM;
break;
}
}
}
pictureBox1.Invalidate();
}
}
}
Note that i have changed your fibonacci function with a better performing one ; in particular, mine calculates the next fibonacci number in linear time.
With some MatheMagic ( sorry for the joke :) ) you can make it even smarter, and obtain
private int move(int n, int a, int currentFib)
{
switch (a)
{
case 1: return currentFib;
case 2: return -fib(n - 1) * ZOOM;
case 3: return -fib(n + 1) * ZOOM;
default: return 0;
}
}
private void drawSpiral()
{
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
Rectangle r = new Rectangle(0, 0, 0, 0);
int x = CENTERX;
int y = CENTERY;
for (int n = 1; n <= FIBNUM; n++)
{
int fibnum = fib(n)*ZOOM;
r = new Rectangle(x, y, fibnum, fibnum);
g.DrawRectangle(Pens.Red, r);
x += move(n, n % 4, fibnum);
y += move(n, (n + 1) % 4, fibnum);
}
pictureBox1.Invalidate();
}
}
private int fib(int n)
{
switch (n)
{
case 0:
return 0;
case 1:
return 1;
default:
return fib(n - 1) + fib(n - 2);
}
}
That is enough slow,maybe it doesn't matter in this task but isn't it better to use an array fib[1..n] (fib[0]=0 fib[1]=1 for(i = 2;i<=n;i++)fib[i]=fib[i-1]+fib[i-2]) that will work in O(n) not in O(n*(1.7^n))

Specifying Duration of sound(tone) created with WaveTone() in NAudio

I want to play a sound(tone) at specified volumes and frequencies but want the duration of playback fixed say 2 seconds.
My code is similar to one given here.
double freq, volume;
WaveTone tone = new WaveTone(freq, volume);
stream = new BlockAlignReductionStream(tone);
output = new DirectSoundOut();
output.Init(stream);
output.Play();
I tried to use latency in DirectSoundOut() above but it did not work as desired. I have to change freq and volume dynamically for each playback.
I need to know the exact duration of playback of tone.
The WaveTone class (assuming you're using one of the ones I just googled) probably provides an endless stream of data. If you want to limit the output to a specific duration you'll need to either load a specific amount of data into another buffer/stream or modify the WaveTone class to stop producing data past the duration.
Something like this:
class WaveTone : WaveStream
{
readonly WaveFormat Format;
public readonly double Frequency;
public readonly double Amplitude;
public readonly double Duration;
readonly long streamLength;
long pos;
const double timeIncr = 1 / 44100.0;
readonly double sinMult;
public WaveTone(double freq, double amp)
: this(freq, amp, 0)
{ }
public WaveTone(double freq, double amp, double dur)
{
Format = new WaveFormat(44100, 16, 1);
Frequency = freq;
Amplitude = Math.Min(1, Math.Max(0, amp));
Duration = dur;
streamLength = Duration == 0 ? long.MaxValue : (long)(44100 * 2 * Duration);
pos = 0;
sinMult = Math.PI * 2 * Frequency;
}
public override WaveFormat WaveFormat
{
get { return Format; }
}
public override long Length
{
get { return streamLength; }
}
public override long Position
{
get { return pos; }
set { pos = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
if (pos >= streamLength)
return 0;
int nSamples = count / 2;
if ((pos + nSamples * 2) > streamLength)
nSamples = (int)(streamLength - pos) / 2;
double time = pos / (44100 * 2.0);
int rc = 0;
for (int i = 0; i < nSamples; i++, time += timeIncr, ++rc, pos += 2)
{
double val = Amplitude * Math.Sin(sinMult * time);
short sval = (short)(Math.Round(val * (short.MaxValue - 1)));
buffer[offset + i * 2] = (byte)(sval & 0xFF);
buffer[offset + i * 2 + 1] = (byte)((sval >> 8) & 0xFF);
}
return rc * 2;
}
}

Bug with repeat sine sound

What is my code:
void SpeakThreadFunction()
{
while (SpeakThreadState)
{
Speaker.Play();
Thread.Sleep(100);
Speaker.Stop()
Thread.Sleep(Interval);
}
}
//Speaker is WaveOut
And Speaker.Init is SineWaveProvider32.
public class SineWaveProvider32 : WaveProvider32
{
int sample;
public SineWaveProvider32()
{
Frequency = 1000;
Amplitude = 0.25f;
}
public float Frequency { get; set; }
public float Amplitude { get; set; }
public override int Read(float[] buffer, int offset, int sampleCount)
{
int sampleRate = WaveFormat.SampleRate;
for (int n = 0; n < sampleCount; n++)
{
buffer[n + offset] = (float)(Amplitude * Math.Sin((2 * Math.PI * sample * Frequency) / sampleRate));
sample++;
if (sample >= sampleRate) sample = 0;
}
return sampleCount;
}
}
After 10-15 iterations on my cycle, sound is stop :(. What i need to do, to my sound repeat all time?
You won't have much success trying to continually start and stop the soundcard like that. The default WaveOut buffer sizes in NAudio are 100ms long. It would be much better to open the soundcard once, and then send it portions of sine wave, followed by zeroes, to create the sound you want.

Categories