How to use this code?!

Duarte Vinagre 60 Reputation points
2023-07-15T13:11:26.4933333+00:00

Hello...i know im making too many questions but im learnning C#...i have this code...i want to detect the BPM of an MP3 file...but i do not know how to use it properly...can someone point me a direction?

using NAudio.Wave;

namespace BPMDetect
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        
        }

        class BPMDetector
        {
            private string filename = null;
            private short[] leftChn;
            private short[] rightChn;
            private double BPM;
            private double sampleRate = 44100;
            private double trackLength = 0;

            public double getBPM()
            {
                return BPM;
            }

            public BPMDetector(string filename)
            {
                this.filename = filename;
                Detect();
            }

            public BPMDetector(short[] leftChn, short[] rightChn)
            {
                this.leftChn = leftChn;
                this.rightChn = rightChn;
                Detect();
            }

            private void Detect()
            {
                if (filename != null)
                {
                    using (WaveFileReader reader = new WaveFileReader(filename))
                    {
                        byte[] buffer = new byte[reader.Length];
                        int read = reader.Read(buffer, 0, buffer.Length);
                        short[] sampleBuffer = new short[read / 2];
                        Buffer.BlockCopy(buffer, 0, sampleBuffer, 0, read);

                        List<short> chan1 = new List<short>();
                        List<short> chan2 = new List<short>();

                        for (int i = 0; i < sampleBuffer.Length; i += 2)
                        {
                            chan1.Add(sampleBuffer[i]);
                            chan2.Add(sampleBuffer[i + 1]);
                        }

                        leftChn = chan1.ToArray();
                        rightChn = chan2.ToArray();
                    }
                }

                trackLength = (float)leftChn.Length / sampleRate;

                // 0.1s window ... 0.1*44100 = 4410 samples, lets adjust this to 3600 
                int sampleStep = 3600;

                // calculate energy over windows of size sampleSetep
                List<double> energies = new List<double>();
                for (int i = 0; i < leftChn.Length - sampleStep - 1; i += sampleStep)
                {
                    energies.Add(rangeQuadSum(leftChn, i, i + sampleStep));
                }

                int beats = 0;
                double average = 0;
                double sumOfSquaresOfDifferences = 0;
                double variance = 0;
                double newC = 0;
                List<double> variances = new List<double>();

                // how many energies before and after index for local energy average
                int offset = 10;

                for (int i = offset; i <= energies.Count - offset - 1; i++)
                {
                    // calculate local energy average
                    double currentEnergy = energies[i];
                    double qwe = rangeSum(energies.ToArray(), i - offset, i - 1) + currentEnergy + rangeSum(energies.ToArray(), i + 1, i + offset);
                    qwe /= offset * 2 + 1;

                    // calculate energy variance of nearby energies
                    List<double> nearbyEnergies = energies.Skip(i - 5).Take(5).Concat(energies.Skip(i + 1).Take(5)).ToList<double>();
                    average = nearbyEnergies.Average();
                    sumOfSquaresOfDifferences = nearbyEnergies.Select(val => (val - average) * (val - average)).Sum();
                    variance = (sumOfSquaresOfDifferences / nearbyEnergies.Count) / Math.Pow(10, 22);

                    // experimental linear regression - constant calculated according to local energy variance
                    newC = variance * 0.009 + 1.385;
                    if (currentEnergy > newC * qwe)
                        beats++;
                }

                BPM = beats / (trackLength / 60);

            }

            private static double rangeQuadSum(short[] samples, int start, int stop)
            {
                double tmp = 0;
                for (int i = start; i <= stop; i++)
                {
                    tmp += Math.Pow(samples[i], 2);
                }

                return tmp;
            }

            private static double rangeSum(double[] data, int start, int stop)
            {
                double tmp = 0;
                for (int i = start; i <= stop; i++)
                {
                    tmp += data[i];
                }

                return tmp;
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            
        }
    }

}



i tried to create an object using

BPMDetector dtc = new BPMDetector();

but no luck!!!

Thanks!

Developer technologies C#
0 comments No comments
{count} votes

Accepted answer
  1. Konstantinos Passadis 19,586 Reputation points MVP
    2023-07-15T14:19:21.34+00:00

    Hello @Duarte Vinagre !

    You can create as much questions as you like and need !

    The purpose of the Community QnA is exactly this , so do not feel sorry !

    On your case :

    The BPMDetector class in your code does not have a parameterless constructor (i.e., one that can be called with no arguments). There are two constructors defined, both of which require parameters:

    1. public BPMDetector(string filename) - requires the filename of the music file you want to analyze.
    2. public BPMDetector(short[] leftChn, short[] rightChn) - requires two arrays of short values representing the left and right audio channels. Therefore, you can't create an instance of BPMDetector with new BPMDetector(). You have to provide the required arguments.

    So, for instance, if you have a music file named "song.mp3" and you want to create an instance of BPMDetector for this file, you would use:

    BPMDetector dtc = new BPMDetector("song.mp3");
    

    After creating an instance of BPMDetector, you can call getBPM() to get the detected beats per minute (BPM):

    double bpm = dtc.getBPM();
    

    So, your button click event handler might look like this:

    private void button1_Click(object sender, EventArgs e)
    {
        BPMDetector dtc = new BPMDetector("song.mp3");
        double bpm = dtc.getBPM();
        MessageBox.Show($"The BPM is {bpm}");
    }
    

    This would display a message box with the detected BPM when the button is clicked.

    Please replace "song.mp3" with the correct path to your music file. The path can be absolute or relative to the executable file of your application. If the music file is in the same directory as the executable, only the filename is needed.

    Here are some examples to look up :

    https://csharp.hotexamples.com/examples/NAudio.Wave/WaveFileReader/-/php-wavefilereader-class-examples.html


    I hope this helps!

    The answer or portions of it may have been assisted by AI Source: ChatGPT Subscription

    Kindly mark the answer as Accepted and Upvote in case it helped or post your feedback to help !

    Regards


1 additional answer

Sort by: Most helpful
  1. Konstantinos Passadis 19,586 Reputation points MVP
    2023-07-15T15:07:51.97+00:00

    Hello @Duarte Vinagre !

    Thank you for the update !

    I am glad you got it !

    For improved accuracy, you could look into more sophisticated algorithms or libraries. Here are a few suggestions:

    ***Librosa**: Although it's a Python library, Librosa has a lot of advanced functionality for audio and music analysis, including tempo and beat detection.*
    
    ***Aubio**: This is another comprehensive audio analysis library. It has a Python interface but is written in C, so you could potentially use it from a C# application as well.*
    
    ***Essentia**: Essentia is a C++ library for audio analysis and content-based music information retrieval. It includes algorithms for computing rhythmic descriptors such as BPM.*
    
    ***Sonic API**: An online API that can analyze an audio file and extract various features, including BPM.*
    
    ***Echo Nest API**: This is another online API that can analyze an audio file and return detailed information, including rhythmic features.*
    

    In some cases, you might want to preprocess your audio to isolate the rhythmic components, such as by applying an equalizer or a high-pass filter to emphasize the beats. You might also want to look at beat tracking algorithms, which aim to follow the beat throughout a piece of music and can handle changes in tempo.

    Remember that, in some cases, even with sophisticated algorithms, detecting the BPM programmatically might not always agree with a human listener's perception, because humans are sensitive to musical factors that are difficult to quantify.

    Lastly, consider that the tempo or BPM of a song can sometimes be subjective and different sources might give slightly different BPMs for the same song. A human tapper may also perceive the BPM differently than a computer algorithm.

    I hope this helps!

    The answer or portions of it may have been assisted by AI Source: ChatGPT Subscription

    Kindly mark the answer as Accepted and Upvote in case it helped!

    Regards


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.