求调教:FFT与扒谱

来源:百度文库 编辑:超级军网 时间:2024/04/29 19:21:14
扒谱扒到纠结了……
应当有一种辅助工具,能人工选定曲子里的一段,算FFT,然后看频率峰图,就知道有哪几个音和声了。
谁知道怎么获得音频数据流?现在有哪些FFT的API?扒谱扒到纠结了……
应当有一种辅助工具,能人工选定曲子里的一段,算FFT,然后看频率峰图,就知道有哪几个音和声了。
谁知道怎么获得音频数据流?现在有哪些FFT的API?
完全不懂的说{:wu:}
路过 同围观··
完全不知道格林达姆娘说的是什么,只有友情围观了
欢迎天顶星人来地球参观访问。
一牧月 发表于 2010-10-18 10:43

发现我不用自己干了,这个软件已经存在了
Audacity,还是开源免费的,功能巨强大
jiandingzhe 发表于 2010-10-18 15:41


    这不,求人不如求己嘛{:wu:}
LPC2103 发表于 2010-10-18 17:38

但是那个软件没有时间-频谱分布图,光看强度图看不出在哪段。杯具了。
难道要老子自己开发扩展么……[:a11:]
jiandingzhe 发表于 2010-10-18 17:42


    这个对你来说木有压力啦@
博丽灵梦 发表于 2010-10-18 18:05

咱几乎没有用过C和C++,完全没有接触过媒体流……


炼成了,咩哈哈哈哈!!
依然有一个会导致segmentation fault的地方,非常诡异,只能人工限制循环数。
修改完成!

  1. #!/usr/bin/perl

  2. use strict;
  3. use feature qw/say/;

  4. use Cairo;

  5. use Getopt::Long;
  6. use Math::Trig qw/pip2/;
  7. use PDL;
  8. use PDL::Audio;

  9. use POSIX();

  10. use constant PITCH_STEP => 2**( 1 / 12 );

  11. my $file_in;
  12. my $file_out;
  13. my $time_grid_interval = 1;
  14. my $window_sz          = 16384;
  15. my $window_step        = 512;
  16. my $page_width         = 2000;

  17. my $freq_from = 50;
  18. my $freq_to   = 7040;

  19. GetOptions(
  20.         'in=s'   => \$file_in,
  21.         'out=s'  => \$file_out,
  22.         'size=i' => \$window_sz,
  23.         'step=i' => \$window_step
  24. );

  25. my $pdl        = raudio $file_in;
  26. my $sz         = $pdl->getdim(0);
  27. my $audio_rate = $pdl->rate;
  28. say "length: $sz";
  29. say "audio sampling rate: $audio_rate";

  30. my $window = gen_fft_window $window_sz, 'hamming';

  31. my $data;

  32. my $use_spec_from = POSIX::floor( $freq_from * $window_sz / $audio_rate );
  33. my $use_spec_to   = calc_use_spectrum_sz();
  34. my $scale_rate   = log( $use_spec_to / $use_spec_from ) / $page_width - 0.00001;
  35. my $page_deviate = log($use_spec_from) / $scale_rate;
  36. my $stride       = Cairo::Format::stride_for_width( 'argb32', $page_width );
  37. my $spec_count   = 0;

  38. say "fft result used: $use_spec_from - $use_spec_to";

  39. for ( my $i = 0 ; $i < $sz ; $i += $window_step ) {
  40.         $spec_count++;
  41.         my $end = $i + $window_sz - 1;

  42.         say "$spec_count: $i - $end of $sz";

  43.         my $sliced = $pdl->slice("$i:$end");
  44.         my $spec = spectrum $sliced, 1, $window;

  45.         #        for ( my $j = 0 ; $j < $spec_sz ; $j++ ) {
  46.         #                my $value = POSIX::floor( 255 * abs( $spec->at($j) ) );
  47.         #                $data .= pack 'CCCC', $value, $value, $value, 255;
  48.         #        }

  49.         for ( my $j = 0 ; $j < $page_width ; $j++ ) {
  50.                 my $index = POSIX::floor( exp( ( $j + $page_deviate ) * $scale_rate ) );
  51.                 my $index2 =
  52.                   POSIX::floor( exp( ( $j + $page_deviate + 1 ) * $scale_rate ) );

  53.                 my $value;
  54.                 if ( $index = $index2 ) {
  55.                         $value = POSIX::floor( 255 * abs( $spec->at($index) ) );
  56.                 }
  57.                 else {
  58.                         my $sum;
  59.                         for ( $index .. $index2 ) {
  60.                                 $sum += POSIX::floor( 255 * abs( $spec->at($_) ) );
  61.                         }
  62.                         $value = $sum / ( $index2 - $index + 1 );
  63.                 }
  64.                 $data .= pack 'CCCC', $value, $value, $value, 255;
  65.         }

  66.         if ( $end >= $sz - $window_step ) {
  67.                 last;
  68.         }
  69. }

  70. say "picture size: w $page_width, h $spec_count";
  71. say "stride size : $stride";
  72. say "graphic data size : ", length($data);
  73. say "height from stride: ", length($data) / $stride;

  74. my $surface =
  75.   Cairo::ImageSurface->create_for_data( $data, 'argb32', $page_width,
  76.         $spec_count, $stride );

  77. draw_grid($surface);

  78. $surface->write_to_png($file_out);

  79. sub calc_use_spectrum_sz {
  80.         my $bottom = 20 * $window_sz / $audio_rate;
  81.         my $half   = POSIX::floor( $window_sz / 2 - $bottom );
  82.         my $freq_limit =
  83.           POSIX::floor( $freq_to * $window_sz / $audio_rate - $bottom );
  84.         return $freq_limit < $half ? $freq_limit : $half;
  85. }

  86. sub draw_grid {
  87.         my $face = shift;

  88.         my $cr = Cairo::Context->create($face);
  89.         $cr->set_source_rgb( 0, 1, 1 );
  90.         $cr->set_line_width(0.5);

  91.         my $time_grid_sz = $time_grid_interval * $audio_rate / $window_step;

  92.         my @pitch_cycle = qw/C C# D D# E F F# G G# A A# B/;
  93.         my $freq_C = 440 * ( PITCH_STEP**3 ) / 2;

  94.         for (
  95.                 my $y = 0, my $y_step = 0 ;
  96.                 $y < $spec_count ;
  97.                 $y += $time_grid_sz, $y_step++
  98.           )
  99.         {
  100.                 $cr->move_to( 0, $y );
  101.                 $cr->line_to( $page_width, $y );
  102.                 $cr->stroke;
  103.                 $cr->move_to( 0, $y );
  104.                 $cr->show_text( $y_step * $time_grid_interval );

  105.                 # draw frequency
  106.                 my $upper_i     = 0;
  107.                 my $upper_cycle = 4;
  108.                 for ( my $f = $freq_C ; $f < $freq_to ; $f *= PITCH_STEP ) {
  109.                         my $x =
  110.                           log( $f * $window_sz / $audio_rate ) / $scale_rate -
  111.                           $page_deviate;
  112.                         $cr->save;
  113.                         $cr->translate( $x, $y );
  114.                         $cr->rotate( -pip2 );
  115.                         $cr->move_to( 0, 0 );
  116.                         $cr->show_text( $pitch_cycle[$upper_i] . $upper_cycle );
  117.                         $cr->restore;
  118.                        
  119.                         $cr->move_to($x,$y);
  120.                         $cr->line_to($x,$y+5);
  121.                         $cr->stroke;

  122.                         $upper_i++;
  123.                         if ( $upper_i == 12 ) {
  124.                                 $upper_i -= 12;
  125.                                 $upper_cycle++;
  126.                         }
  127.                 }

  128.                 my $lower_i     = 11;
  129.                 my $lower_cycle = 3;
  130.                 for ( my $f = $freq_C / PITCH_STEP ;
  131.                         $f > $freq_from ; $f /= PITCH_STEP )
  132.                 {
  133.                         my $x =
  134.                           log( $f * $window_sz / $audio_rate ) / $scale_rate -
  135.                           $page_deviate;
  136.                        
  137.                         $cr->save;
  138.                         $cr->translate( $x, $y );
  139.                         $cr->rotate( -pip2 );
  140.                         $cr->move_to( 0, 0 );
  141.                         $cr->show_text( $pitch_cycle[$lower_i] . $lower_cycle );
  142.                         $cr->restore;
  143.                        
  144.                         $cr->move_to($x,$y);
  145.                         $cr->line_to($x,$y+5);
  146.                         $cr->stroke;

  147.                         $lower_i--;
  148.                         if ( $lower_i == -1 ) {
  149.                                 $lower_i += 12;
  150.                                 $lower_cycle--;
  151.                         }
  152.                 }
  153.         }

  154. }

复制代码


炼成了,咩哈哈哈哈!!
依然有一个会导致segmentation fault的地方,非常诡异,只能人工限制循环数。
修改完成!

  1. #!/usr/bin/perl

  2. use strict;
  3. use feature qw/say/;

  4. use Cairo;

  5. use Getopt::Long;
  6. use Math::Trig qw/pip2/;
  7. use PDL;
  8. use PDL::Audio;

  9. use POSIX();

  10. use constant PITCH_STEP => 2**( 1 / 12 );

  11. my $file_in;
  12. my $file_out;
  13. my $time_grid_interval = 1;
  14. my $window_sz          = 16384;
  15. my $window_step        = 512;
  16. my $page_width         = 2000;

  17. my $freq_from = 50;
  18. my $freq_to   = 7040;

  19. GetOptions(
  20.         'in=s'   => \$file_in,
  21.         'out=s'  => \$file_out,
  22.         'size=i' => \$window_sz,
  23.         'step=i' => \$window_step
  24. );

  25. my $pdl        = raudio $file_in;
  26. my $sz         = $pdl->getdim(0);
  27. my $audio_rate = $pdl->rate;
  28. say "length: $sz";
  29. say "audio sampling rate: $audio_rate";

  30. my $window = gen_fft_window $window_sz, 'hamming';

  31. my $data;

  32. my $use_spec_from = POSIX::floor( $freq_from * $window_sz / $audio_rate );
  33. my $use_spec_to   = calc_use_spectrum_sz();
  34. my $scale_rate   = log( $use_spec_to / $use_spec_from ) / $page_width - 0.00001;
  35. my $page_deviate = log($use_spec_from) / $scale_rate;
  36. my $stride       = Cairo::Format::stride_for_width( 'argb32', $page_width );
  37. my $spec_count   = 0;

  38. say "fft result used: $use_spec_from - $use_spec_to";

  39. for ( my $i = 0 ; $i < $sz ; $i += $window_step ) {
  40.         $spec_count++;
  41.         my $end = $i + $window_sz - 1;

  42.         say "$spec_count: $i - $end of $sz";

  43.         my $sliced = $pdl->slice("$i:$end");
  44.         my $spec = spectrum $sliced, 1, $window;

  45.         #        for ( my $j = 0 ; $j < $spec_sz ; $j++ ) {
  46.         #                my $value = POSIX::floor( 255 * abs( $spec->at($j) ) );
  47.         #                $data .= pack 'CCCC', $value, $value, $value, 255;
  48.         #        }

  49.         for ( my $j = 0 ; $j < $page_width ; $j++ ) {
  50.                 my $index = POSIX::floor( exp( ( $j + $page_deviate ) * $scale_rate ) );
  51.                 my $index2 =
  52.                   POSIX::floor( exp( ( $j + $page_deviate + 1 ) * $scale_rate ) );

  53.                 my $value;
  54.                 if ( $index = $index2 ) {
  55.                         $value = POSIX::floor( 255 * abs( $spec->at($index) ) );
  56.                 }
  57.                 else {
  58.                         my $sum;
  59.                         for ( $index .. $index2 ) {
  60.                                 $sum += POSIX::floor( 255 * abs( $spec->at($_) ) );
  61.                         }
  62.                         $value = $sum / ( $index2 - $index + 1 );
  63.                 }
  64.                 $data .= pack 'CCCC', $value, $value, $value, 255;
  65.         }

  66.         if ( $end >= $sz - $window_step ) {
  67.                 last;
  68.         }
  69. }

  70. say "picture size: w $page_width, h $spec_count";
  71. say "stride size : $stride";
  72. say "graphic data size : ", length($data);
  73. say "height from stride: ", length($data) / $stride;

  74. my $surface =
  75.   Cairo::ImageSurface->create_for_data( $data, 'argb32', $page_width,
  76.         $spec_count, $stride );

  77. draw_grid($surface);

  78. $surface->write_to_png($file_out);

  79. sub calc_use_spectrum_sz {
  80.         my $bottom = 20 * $window_sz / $audio_rate;
  81.         my $half   = POSIX::floor( $window_sz / 2 - $bottom );
  82.         my $freq_limit =
  83.           POSIX::floor( $freq_to * $window_sz / $audio_rate - $bottom );
  84.         return $freq_limit < $half ? $freq_limit : $half;
  85. }

  86. sub draw_grid {
  87.         my $face = shift;

  88.         my $cr = Cairo::Context->create($face);
  89.         $cr->set_source_rgb( 0, 1, 1 );
  90.         $cr->set_line_width(0.5);

  91.         my $time_grid_sz = $time_grid_interval * $audio_rate / $window_step;

  92.         my @pitch_cycle = qw/C C# D D# E F F# G G# A A# B/;
  93.         my $freq_C = 440 * ( PITCH_STEP**3 ) / 2;

  94.         for (
  95.                 my $y = 0, my $y_step = 0 ;
  96.                 $y < $spec_count ;
  97.                 $y += $time_grid_sz, $y_step++
  98.           )
  99.         {
  100.                 $cr->move_to( 0, $y );
  101.                 $cr->line_to( $page_width, $y );
  102.                 $cr->stroke;
  103.                 $cr->move_to( 0, $y );
  104.                 $cr->show_text( $y_step * $time_grid_interval );

  105.                 # draw frequency
  106.                 my $upper_i     = 0;
  107.                 my $upper_cycle = 4;
  108.                 for ( my $f = $freq_C ; $f < $freq_to ; $f *= PITCH_STEP ) {
  109.                         my $x =
  110.                           log( $f * $window_sz / $audio_rate ) / $scale_rate -
  111.                           $page_deviate;
  112.                         $cr->save;
  113.                         $cr->translate( $x, $y );
  114.                         $cr->rotate( -pip2 );
  115.                         $cr->move_to( 0, 0 );
  116.                         $cr->show_text( $pitch_cycle[$upper_i] . $upper_cycle );
  117.                         $cr->restore;
  118.                        
  119.                         $cr->move_to($x,$y);
  120.                         $cr->line_to($x,$y+5);
  121.                         $cr->stroke;

  122.                         $upper_i++;
  123.                         if ( $upper_i == 12 ) {
  124.                                 $upper_i -= 12;
  125.                                 $upper_cycle++;
  126.                         }
  127.                 }

  128.                 my $lower_i     = 11;
  129.                 my $lower_cycle = 3;
  130.                 for ( my $f = $freq_C / PITCH_STEP ;
  131.                         $f > $freq_from ; $f /= PITCH_STEP )
  132.                 {
  133.                         my $x =
  134.                           log( $f * $window_sz / $audio_rate ) / $scale_rate -
  135.                           $page_deviate;
  136.                        
  137.                         $cr->save;
  138.                         $cr->translate( $x, $y );
  139.                         $cr->rotate( -pip2 );
  140.                         $cr->move_to( 0, 0 );
  141.                         $cr->show_text( $pitch_cycle[$lower_i] . $lower_cycle );
  142.                         $cr->restore;
  143.                        
  144.                         $cr->move_to($x,$y);
  145.                         $cr->line_to($x,$y+5);
  146.                         $cr->stroke;

  147.                         $lower_i--;
  148.                         if ( $lower_i == -1 ) {
  149.                                 $lower_i += 12;
  150.                                 $lower_cycle--;
  151.                         }
  152.                 }
  153.         }

  154. }

复制代码
GOOD JOB!
LPC2103 发表于 2010-10-28 10:32

简单的FFT已经不能填满我的欲望了!!我要神经网络!!