示例#1
0
        static void Main(string[] args)
        {
            if(args.Length<1){
                Console.WriteLine("Usage: BPMAnalyzer <filename>.wav");
                return;
            }

            var waveFile=new WaveFile(args[0]);

            const int frameSize=1024;
            var frameCount=(double)waveFile.FormatChunk.SamplesPerSecond/frameSize;
            var dataLength=waveFile.Data.Length;
            var sampleCount=dataLength/frameSize/2;
            var data=waveFile.Data.ToList();
            var volume=(from index in Enumerable.Range(0,sampleCount)
                        let sum=data.GetRange(frameSize*index,frameSize).Sum(d=>(double)d*d)
                        select Math.Sqrt(sum/frameSize)).ToArray();

            waveFile.Dispose();

            var prev=0.0;
            var diff=(from v in volume let temp=prev select Math.Max((prev=v)-temp,0.0)).ToArray();

            var indices=Enumerable.Range(0,diff.Length).AsParallel();
            var r=(from i in Enumerable.Range(0,181)
                   let freq=(i+60)/60.0
                   let theta=2.0*Math.PI*freq/frameCount
                   let cosSum=indices.Sum(index=>HannWindow(index,diff.Length)*Math.Cos(theta*index)*diff[index])/sampleCount
                   let sinSum=indices.Sum(index=>HannWindow(index,diff.Length)*Math.Sin(theta*index)*diff[index])/sampleCount
                   select new{A=cosSum,B=sinSum,R=Math.Sqrt(cosSum*cosSum+sinSum*sinSum)}).ToArray();

            var peaks=FindPeak(r.Select(obj=>obj.R).ToArray(),3);

            for(int i=0;i<peaks.Length;i++){
                Console.WriteLine("[{0}]",i+1);
                int bpm=peaks[i]+60;
                Console.WriteLine("Peak BPM: {0}",bpm);
                var theta=Math.Atan2(r[peaks[i]].B,r[peaks[i]].A);
                if(theta<0) theta+=2.0*Math.PI;
                var peakFreq=(double)bpm/60;
                var startTime=theta/(2.0*Math.PI*peakFreq);
                var startBeat=theta/(2.0*Math.PI);
                Console.WriteLine("First beat time: {0} sec",startTime);
                Console.WriteLine("First beat: {0} beat",startBeat);
            }
        }