This project has moved. For the latest updates, please go here.

DirectSoundOut isn't fluent stream after passing effect (NAudio, C#)

May 19 at 7:57 AM
Hi guys,
I've got a problem with playing me stream by DirectSoundOut. I open same wav file by OpenFileDialog - It's Ok, Then read data from wav file and convert them to float, then I apply my function for effecting that samples, and conver them to byte[] and read - and now start the problem when the stream of effected data is in DirectSoundOut - I can't hear fluent, effected sound but it sounds like one sample is played more times, its change when i change latency, but if I've got small latency, I can't hear sound and when I raise latency, I've got problem, which I described above.
I think, It becase:
1) This process is to time-consuming, and data are not being processed in this time, becase my function for effecting is transfer function, which can be variable in time - you got graph of this function and you can change possition of points of this graph and on this point is applied polynomial regression to get function with parametr, this method I call in Read method and fit samples to the equation.
2) I can't found the best latency...
        private BlockAlignReductionStream stream = null;
        private NAudio.Wave.DirectSoundOut output = null;
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "Wave File (*.wav)|*.wav;";
            if (open.ShowDialog() != DialogResult.OK) return;
            textBox1.Text = open.FileName;
            WaveChannel32 wave = new WaveChannel32(new WaveFileReader(open.FileName));
            EffectStream effect = new EffectStream(wave);
            stream = new BlockAlignReductionStream(effect);
            output = new DirectSoundOut();
            output.Init(stream);
            output.Play();
            button2.Enabled = true;
            chart1.Enabled = true;
        }
this is part of code, where I try to open file and play effected file
 public float getFunction(float x)
        {
           double[] arrayX = new double[chart1.Series[0].Points.Count()]; // Získáme polohu bodů z grafu na ose x
           double[] arrayY = new double[chart1.Series[0].Points.Count()];// Získáme polohu bodů z grafu na ose y
           double[] arrayResult = { };

            for (int i = 0; i < chart1.Series[0].Points.Count(); i++) // naplnění 
            {

                arrayX[i] = (chart1.Series[0].Points[i].XValue);
                arrayY[i] = (chart1.Series[0].Points[i].YValues[0]);
            }
            arrayResult = (PolyRegression.Polyfit(arrayX, arrayY, 8)); // instance of class PolyRegression for solving a system of equation
            // System of equation,  functionVarA-E are coefficients 
            double functionVarI = arrayResult[0];
            double functionVarH = arrayResult[1];
            double functionVarG = arrayResult[2];
            double functionVarF = arrayResult[3];
            double functionVarE = arrayResult[4]; 
            double functionVarD = arrayResult[5];
            double functionVarC = arrayResult[6];
            double functionVarB = arrayResult[7];
            double functionVarA = arrayResult[8];
            double equationVar = 0;

            equationVar = functionVarA * (Math.Pow(x, 8)) + functionVarB * (Math.Pow(x, 7)) + functionVarC * (Math.Pow(x, 6)) + functionVarD * (Math.Pow(x, 5)) + functionVarE * (Math.Pow(x, 4)) + functionVarF * (Math.Pow(x, 3)) + functionVarG * (Math.Pow(x, 2)) + functionVarH * x + functionVarI; // Transfer function
            float Transfer = Convert.ToSingle(equationVar); //Convert to float
            return Transfer; .
        }
this is code for getting transfer function from graph
public class PolyRegression
    {
        public static double[] Polyfit(double[] x, double[] y, int degree)
    {
        // Count of coefficients from system of equations, plynimial regression 
        var v = new DenseMatrix(x.Length, degree + 1);
        for (int i = 0; i < v.RowCount; i++)
            for (int j = 0; j <= degree; j++) v[i, j] = Math.Pow(x[i], j);// v[i, j] - levá strana rovnice, Math.Pow(x[i],j) - pravá strana 
        var yv = new DenseVector(y).ToColumnMatrix();
        QR qr = v.QR(); // triangle matrix
        var r = qr.R.SubMatrix(0, degree + 1, 0, degree + 1);
        var q = v.Multiply(r.Inverse());
        var p = r.Inverse().Multiply(q.TransposeThisAndMultiply(yv));
        return p.Column(0).ToArray();
    }
    }
this is how I solve coeffincients
public override int Read(byte[] buffer, int offset, int count)
        {
            Console.WriteLine("DirectSoundOut requested {0} bytes", count);

            int read = SourceStream.Read(buffer, offset, count);
           
            for (int i = 0; i < read / 4 ; i++)
            {
                float sample = BitConverter.ToSingle(buffer, i * 4 );
                        sample = frm.getFunction(sample);
               
                  byte[] bytes = BitConverter.GetBytes(sample);
                  buffer[i * 4 + 0] = bytes[0];
                  buffer[i * 4 + 1] = bytes[1];
                  buffer[i * 4 + 2] = bytes[2];
                  buffer[i * 4 + 3] = bytes[3];
                  
            }

            return read;
        }
and this is my read function in EffectStream

So guys, heve you got any idea, what I have to do? I need hear fluent effected sound.
Thank you so much for your advices and comments. :-)
May 19 at 4:32 PM
Your Read method seems correct to me, so I assume your "getFunction" is causing the problems.

Also you can discard BlockAlignReductionStream, as it is not needed here.
May 23 at 11:13 AM
Could I ask? I this project I want to apply waveshaper effect and but with changing transfer function - getFunction(double x) - is my stransfer function, and I get I when I take position of points from my chart and apply Polyregression to get polynomial function equationVar = functionVarA * (Math.Pow(x, 8)) + functionVarB * (Math.Pow(x, 7)) + functionVarC * (Math.Pow(x, 6)) + functionVarD * (Math.Pow(x, 5)) + functionVarE * (Math.Pow(x, 4)) + functionVarF * (Math.Pow(x, 3)) + functionVarG * (Math.Pow(x, 2)) + functionVarH * x + functionVarI.
And than I want to play this effected destroyed sound - when I click play button I want to hear effected sound insted of my wav file sound, and still I want to have chance to changing transfer function when I played audio.
And my problem is / If I apply this function on read method - I can't hear fluent effected sound.
So I aks. Is any solution for waveshaper effect in NAudio?
I'll be soooo gratefull for answer. Thank you so much...
May 24 at 8:08 PM
As I said before, I assume your poly function is doing the distortions.

Here is an example how to do realtime effects with NAudio.
May 25 at 7:28 AM
Yes, my polyfuction is doing distortions and I want to changing parametres functionVarI, functionVarH, functionVarG, functionVarF etc. in realtime by dragging and moving points in chart of my poly function and in real time counting this parameters and play destroyed sound...
May 25 at 12:57 PM
OIC!!!.... I don't have to do fft for apply, just what I have to do is from my chart of function se treshold - is first poin for -values and last point for +value of my input and knee of effect and I don't realy understant how i can implement my other nonlinearities - other points in chart... I will think about it...