コード例 #1
0
        public FingerprintSignature CreateAudioFingerprint(string key, string filename, int startPositionInMS, int toReadInMS)
        {
            SpectrogramConfig spectrogramConfig = new DefaultSpectrogramConfig();

            AudioSamples samples = null;

            try
            {
                // First read audio file and downsample it to mono 5512hz
                samples = audioEngine.ReadMonoFromFile(filename, spectrogramConfig.SampleRate, startPositionInMS, toReadInMS);
            }
            catch
            {
                return(null);
            }

            // No slice the audio is chunks seperated by 11,6 ms (5512hz 11,6ms = 64 samples!)
            // An with length of 371ms (5512kHz 371ms = 2048 samples [rounded])

            FingerprintSignature fingerprint = audioEngine.CreateFingerprint(samples, spectrogramConfig);

            if (fingerprint != null)
            {
                fingerprint.Reference = key;
            }
            return(fingerprint);
        }
コード例 #2
0
        /// <summary>
        /// Read audio file and mix it to mono, then resample it to "samplerate"
        /// </summary>
        /// <param name="filename">Name of the file</param>
        /// <param name="samplerate">Output sample rate, default 5512hz</param>
        /// <param name="toReadInMS">Milliseconds to read of or <= 0 to read everything</param>
        /// <param name="startmillisecond">Start position in millisecond, default 0 for begin</param>
        /// <returns>Array of samples</returns>
        /// <remarks>
        /// Seeking capabilities of Bass where not used because of the possible
        /// timing errors on different formats.
        /// </remarks>
        public AudioSamples ReadMonoFromFile(string filename, int outputSamplerate = 5512, int startPositionInMS = 0, int toReadInMS = -1)
        {
            if (!File.Exists(filename))
            {
                throw new Exception("File '" + filename + "' doesn't exists.");
            }

            // calculate total milliseconds to read
            int totalmilliseconds = toReadInMS <= 0 ? Int32.MaxValue : (toReadInMS + startPositionInMS);

            float[] data = null;

            //create streams for re-sampling
            int stream      = CreateStream(filename);
            int mixerStream = CreateMixerStream(outputSamplerate);

            if (!bassService.CombineMixerStreams(mixerStream, stream, BASSFlag.BASS_MIXER_FILTER | BASSFlag.BASS_MIXER_DOWNMIX))
            {
                throw new BassException(bassService.GetLastError());
            }

            int bufferSize = outputSamplerate * 10 * 4; /*read 10 seconds at each iteration*/

            float[]        buffer = new float[bufferSize];
            List <float[]> chunks = new List <float[]>();
            int            size   = 0;

            while ((float)(size) / outputSamplerate * 1000 < totalmilliseconds)
            {
                // get re-sampled/mono data
                int bytesRead = Bass.BASS_ChannelGetData(mixerStream, buffer, bufferSize);
                if (bytesRead == 0)
                {
                    break;
                }
                float[] chunk = new float[bytesRead / 4]; //each float contains 4 bytes
                Array.Copy(buffer, chunk, bytesRead / 4);
                chunks.Add(chunk);
                size += bytesRead / 4; //size of the data
            } //while

            if ((float)(size) / outputSamplerate * 1000 < (toReadInMS + startPositionInMS))
            {
                // not enough samples to return the requested data
                return(null);
            }

            // Do bass cleanup
            Bass.BASS_ChannelStop(mixerStream);
            Bass.BASS_ChannelStop(stream);
            Bass.BASS_StreamFree(mixerStream);
            Bass.BASS_StreamFree(stream);

            int start = (int)((float)startPositionInMS * outputSamplerate / 1000);
            int end   = (toReadInMS <= 0) ? size : (int)((float)(startPositionInMS + toReadInMS) * outputSamplerate / 1000);

            data = new float[size];
            int index = 0;

            // Concatenate
            foreach (float[] chunk in chunks)
            {
                Array.Copy(chunk, 0, data, index, chunk.Length);
                index += chunk.Length;
            }

            // Select specific part of the song
            if (start != 0 || end != size)
            {
                float[] temp = new float[end - start];
                Array.Copy(data, start, temp, 0, end - start);
                data = temp;
            }

            // Create audiosamples object
            AudioSamples audioSamples = new AudioSamples();

            audioSamples.Origin       = filename;
            audioSamples.Channels     = 1;
            audioSamples.SampleRate   = outputSamplerate;
            audioSamples.StartInMS    = start;
            audioSamples.DurationInMS = end;
            audioSamples.Samples      = data;

            return(audioSamples);
        }
コード例 #3
0
        /// <summary>
        /// Stretches audio, keeps channels and samplerate.
        /// negatief value slowsdown (makes longer) the audio
        /// Positief value speedsup (make shorter) the audio
        /// </summary>
        public AudioSamples TimeStretch(float[] inputAudioSamples, int inputSampleRate = 44100, int inputChannels = 2, float rateFactor = 0.0f)
        {
            // calculate total milliseconds to read
            int totalmilliseconds = Int32.MaxValue;

            float[] data = null;

            int stream = Bass.BASS_StreamCreatePush(inputSampleRate, inputChannels, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero);

            ThrowIfStreamIsInvalid(stream);
            BASS_CHANNELINFO channelInfo = Bass.BASS_ChannelGetInfo(stream);

            Bass.BASS_StreamPutData(stream, inputAudioSamples, inputAudioSamples.Length * 4);

            SoundTouch <Single, Double> soundTouch = new SoundTouch <Single, Double>();

            soundTouch.SetSampleRate(channelInfo.freq);
            soundTouch.SetChannels(channelInfo.chans);
            soundTouch.SetTempoChange(0.0f);
            soundTouch.SetPitchSemiTones(0.0f);
            soundTouch.SetRateChange(rateFactor); // -1.4f = Radio 538 setting
            soundTouch.SetSetting(SettingId.UseQuickseek, 0);
            soundTouch.SetSetting(SettingId.UseAntiAliasFilter, 0);

            int bufferSize = 2048;

            float[]        buffer   = new float[bufferSize];
            List <float[]> chunks   = new List <float[]>();
            int            size     = 0;
            int            nSamples = 0;

            while ((float)(size) / channelInfo.freq * 1000 < totalmilliseconds)
            {
                // get re-sampled data
                int bytesRead = Bass.BASS_ChannelGetData(stream, buffer, bufferSize);
                if (bytesRead <= 0)
                {
                    break;
                }
                nSamples = (bytesRead / 4) / channelInfo.chans;
                // Feed the samples into SoundTouch processor
                soundTouch.PutSamples(buffer, nSamples);

                // Read ready samples from SoundTouch processor & write them output file.
                // NOTES:
                // - 'receiveSamples' doesn't necessarily return any samples at all
                //   during some rounds!
                // - On the other hand, during some round 'receiveSamples' may have more
                //   ready samples than would fit into 'sampleBuffer', and for this reason
                //   the 'receiveSamples' call is iterated for as many times as it
                //   outputs samples.
                do
                {
                    nSamples = soundTouch.ReceiveSamples(buffer, (bufferSize / channelInfo.chans));
                    if (nSamples > 0)
                    {
                        float[] chunk = new float[nSamples * channelInfo.chans];
                        Array.Copy(buffer, chunk, nSamples * channelInfo.chans);
                        chunks.Add(chunk);
                        size += nSamples * channelInfo.chans; //size of the data
                    }
                } while (nSamples != 0);
            } //while

            // Now the input file is processed, yet 'flush' few last samples that are
            // hiding in the SoundTouch's internal processing pipeline.
            soundTouch.Flush();
            do
            {
                nSamples = soundTouch.ReceiveSamples(buffer, (bufferSize / channelInfo.chans));
                if (nSamples > 0)
                {
                    float[] chunk = new float[nSamples * channelInfo.chans];
                    Array.Copy(buffer, chunk, nSamples * channelInfo.chans);
                    chunks.Add(chunk);
                    size += nSamples * channelInfo.chans; //size of the data
                }
            } while (nSamples != 0);


            if (size <= 0)
            {
                // not enough samples to return the requested data
                return(null);
            }

            // Do bass cleanup
            Bass.BASS_ChannelStop(stream);
            Bass.BASS_StreamFree(stream);

            int start = 0;
            int end   = size;

            data = new float[size];
            int index = 0;

            // Concatenate
            foreach (float[] chunk in chunks)
            {
                Array.Copy(chunk, 0, data, index, chunk.Length);
                index += chunk.Length;
            }

            // Select specific part of the song
            if (start != 0 || end != size)
            {
                float[] temp = new float[end - start];
                Array.Copy(data, start, temp, 0, end - start);
                data = temp;
            }

            // Create audiosamples object
            AudioSamples audioSamples = new AudioSamples();

            audioSamples.Origin       = "MEMORY";
            audioSamples.Channels     = channelInfo.chans;
            audioSamples.SampleRate   = channelInfo.freq;
            audioSamples.StartInMS    = start;
            audioSamples.DurationInMS = end;
            audioSamples.Samples      = data;

            return(audioSamples);
        }
コード例 #4
0
        public FingerprintSignature CreateFingerprint(AudioSamples audioSamples, SpectrogramConfig configuration)
        {
            absEnergy      = new double[(Frequencies.Length - 1) * 4];   // number of frequencies bands (33)
            lowpassFilters = new LowpassFilters(Frequencies.Length - 1); // 33 bands
            try
            {
                int width = (audioSamples.Samples.Length - configuration.WdftSize) / configuration.Overlap;  // WdftSize=2048 / Overlap=64
                if (width < 1)
                {
                    return(null);
                }

                // reserve memory for 32 bit fingerprint hashes
                byte[] hashes        = new byte[width * sizeof(uint)];
                byte[] reliabilities = new byte[width * 32]; // elke subfinger (32 bits) heeft voor elke bit een waarde tussen 0 en 31 voor relibility (dus 5 bits), we ronden dit af naar 1 byte
                FingerprintSignature fingerprintSignature = new FingerprintSignature(null, 0, hashes, (long)(width * 11.6));
                fingerprintSignature.Reliabilities = reliabilities;

                // Calculate a hamming windows
                float[] hammingWindow = new float[configuration.WdftSize];
                for (int i = 0; i < hammingWindow.Length; i++)
                {
                    // Hamming (watch it peak is at beginning not as in real hamming in the middle)
                    hammingWindow[i] = 0.54f + 0.46f * (float)System.Math.Cos((6.283f * (float)i / hammingWindow.Length));
                    //hammingWindow[i] = 0.54f - (0.46f * (float)System.Math.Cos(((6.283f * (float)i) / (hammingWindow.Length - 1))));  // real hamming window
                } //for

                int[]   frequenciesRange = Frequencies; // 34 freqencies
                float[] samples          = new float[configuration.WdftSize];

                for (int i = 0; i < width; i++)
                {
                    if (((samples.Length - 1) + (i * configuration.Overlap)) >= audioSamples.Samples.Length)
                    {
                        // we hebben niet voldoende data meer!
                        // dus we stoppen nu en nemen het "laaste" stukje niet mee!
                        break;
                    }

                    for (int j = 0; j < samples.Length; j++)
                    {
                        samples[j] = audioSamples.Samples[j + (i * configuration.Overlap)] * hammingWindow[j];
                    } // for j

                    float[] complexSignal = fftService.FFTForward(samples, 0, configuration.WdftSize);
                    byte[]  reliability;
                    uint    subFingerprint = CalculateSubFingerprint(complexSignal, frequenciesRange, 5512, out reliability);

                    Buffer.BlockCopy(BitConverter.GetBytes(subFingerprint), 0, hashes, i * sizeof(uint), sizeof(uint));
                    Buffer.BlockCopy(reliability, 0, reliabilities, i * reliability.Length, reliability.Length);
                    // sequencenumber = i;
                    // timestamp = (i / audioSamples.Samples.Length) * configuration.SampleRate
                } //for

                return(fingerprintSignature);
            }
            finally
            {
                absEnergy      = null;
                lowpassFilters = null;
            }
        }
コード例 #5
0
        /// <summary>
        /// Resample to new samplerate and in mono
        /// </summary>
        public AudioSamples Resample(float[] inputAudioSamples, int inputSampleRate = 44100, int inputChannels = 2, int outputSamplerate = 5512)
        {
            //create streams for re-sampling
            int stream = Bass.BASS_StreamCreatePush(inputSampleRate, inputChannels, GetDefaultFlags(), IntPtr.Zero);

            ThrowIfStreamIsInvalid(stream);
            int mixerStream = BassMix.BASS_Mixer_StreamCreate(outputSamplerate, 1, GetDefaultFlags());

            ThrowIfStreamIsInvalid(mixerStream);
            if (!bassService.CombineMixerStreams(mixerStream, stream, BASSFlag.BASS_MIXER_FILTER | BASSFlag.BASS_MIXER_DOWNMIX))
            {
                throw new BassException(bassService.GetLastError());
            }
            Bass.BASS_StreamPutData(stream, inputAudioSamples, inputAudioSamples.Length * 4);

            int bufferSize = outputSamplerate * 10 * 4; /*read 10 seconds at each iteration*/

            float[]        buffer = new float[bufferSize];
            List <float[]> chunks = new List <float[]>();
            int            size   = 0;

            int bytesRead;

            do
            {
                // get re-sampled/mono data
                bytesRead = Bass.BASS_ChannelGetData(mixerStream, buffer, bufferSize);
                if (bytesRead == 0)
                {
                    break;
                }
                float[] chunk = new float[bytesRead / 4]; //each float contains 4 bytes
                Array.Copy(buffer, chunk, bytesRead / 4);
                chunks.Add(chunk);
                size += bytesRead / 4; //size of the data
            } while (bytesRead > 0);


            // Do bass cleanup
            Bass.BASS_ChannelStop(mixerStream);
            Bass.BASS_ChannelStop(stream);
            Bass.BASS_StreamFree(mixerStream);
            Bass.BASS_StreamFree(stream);

            float[] data  = new float[size];
            int     index = 0;

            // Concatenate
            foreach (float[] chunk in chunks)
            {
                Array.Copy(chunk, 0, data, index, chunk.Length);
                index += chunk.Length;
            }

            // Create audiosamples object
            AudioSamples audioSamples = new AudioSamples();

            audioSamples.Origin       = "MEMORY";
            audioSamples.Channels     = 1;
            audioSamples.SampleRate   = outputSamplerate;
            audioSamples.StartInMS    = 0;
            audioSamples.DurationInMS = (int)(((float)size / (float)outputSamplerate) * 1000.0f);
            audioSamples.Samples      = data;

            return(audioSamples);
        }