public VorbisCachedSound(Stream sound) { using (var audioFileReader = new VorbisWaveReader(sound)) { // TODO: could add resampling in here if required WaveFormat = audioFileReader.WaveFormat; var sp = audioFileReader.ToSampleProvider(); var wholeFile = new List <float>((int)(audioFileReader.Length / 4)); var sourceSamples = (int)(audioFileReader.Length / (audioFileReader.WaveFormat.BitsPerSample / 8)); var sampleData = new float[sourceSamples]; int samplesRead; while ((samplesRead = sp.Read(sampleData, 0, sourceSamples)) > 0) { wholeFile.AddRange(sampleData.Take(samplesRead)); } AudioData = wholeFile.ToArray(); } }
public BPMDetector(string audioFile, int start = 0, int length = 0) { // Load the file if (Path.GetExtension(audioFile) == ".ogg" || Path.GetExtension(audioFile) == ".egg") { using (VorbisWaveReader reader = new VorbisWaveReader(audioFile)) { // Originally the sample rate was constant (44100), and the number of channels was 2. // Let's just in case take them from file's properties sampleRate = reader.WaveFormat.SampleRate; channels = reader.WaveFormat.Channels; int bytesPerSample = reader.WaveFormat.BitsPerSample / 8; if (bytesPerSample == 0) { bytesPerSample = 2; // assume 16 bit } int sampleCount = (int)reader.Length / bytesPerSample; // Read the wave data start *= channels * sampleRate; length *= channels * sampleRate; if (start >= sampleCount) { groups = new BPMGroup[0]; return; } if (length == 0 || start + length >= sampleCount) { length = sampleCount - start; } length = (int)(length / channels) * channels; ISampleProvider sampleReader = reader.ToSampleProvider(); float[] samples = new float[length]; sampleReader.Read(samples, start, length); // Beats, or kicks, generally occur around the 100 to 150 hz range. // Below this is often the bassline. So let's focus just on that. for (int ch = 0; ch < channels; ++ch) { // First a lowpass to remove most of the song. BiQuadFilter lowpass = BiQuadFilter.LowPassFilter(sampleRate, 150.0F, 1.0F); // Now a highpass to remove the bassline. BiQuadFilter highpass = BiQuadFilter.HighPassFilter(sampleRate, 100.0F, 1.0F); for (int i = ch; i < length; i += channels) { samples[i] = highpass.Transform(lowpass.Transform(samples[i])); } } Peak[] peaks = getPeaks(samples); BPMGroup[] allGroups = getIntervals(peaks); Array.Sort(allGroups, (x, y) => y.Count.CompareTo(x.Count)); if (allGroups.Length > 5) { Array.Resize(ref allGroups, 5); } this.groups = allGroups; } } else { using (MediaFoundationReader reader = new MediaFoundationReader(audioFile)) { // Originally the sample rate was constant (44100), and the number of channels was 2. // Let's just in case take them from file's properties sampleRate = reader.WaveFormat.SampleRate; channels = reader.WaveFormat.Channels; int bytesPerSample = reader.WaveFormat.BitsPerSample / 8; if (bytesPerSample == 0) { bytesPerSample = 2; // assume 16 bit } int sampleCount = (int)reader.Length / bytesPerSample; // Read the wave data start *= channels * sampleRate; length *= channels * sampleRate; if (start >= sampleCount) { groups = new BPMGroup[0]; return; } if (length == 0 || start + length >= sampleCount) { length = sampleCount - start; } length = (int)(length / channels) * channels; ISampleProvider sampleReader = reader.ToSampleProvider(); float[] samples = new float[length]; sampleReader.Read(samples, start, length); // Beats, or kicks, generally occur around the 100 to 150 hz range. // Below this is often the bassline. So let's focus just on that. for (int ch = 0; ch < channels; ++ch) { // First a lowpass to remove most of the song. BiQuadFilter lowpass = BiQuadFilter.LowPassFilter(sampleRate, 150.0F, 1.0F); // Now a highpass to remove the bassline. BiQuadFilter highpass = BiQuadFilter.HighPassFilter(sampleRate, 100.0F, 1.0F); for (int i = ch; i < length; i += channels) { samples[i] = highpass.Transform(lowpass.Transform(samples[i])); } } Peak[] peaks = getPeaks(samples); BPMGroup[] allGroups = getIntervals(peaks); Array.Sort(allGroups, (x, y) => y.Count.CompareTo(x.Count)); if (allGroups.Length > 5) { Array.Resize(ref allGroups, 5); } this.groups = allGroups; } } }