Hatena::Groupnicovideo

にわかな奴の砂場

    使えそうなものがあれば適当にどうぞ。(自己責任的な意味で) 過去ログ

2007-09-29

[][] 小節とか拍をフレーム・サンプルの位置と対応付けるスクリプト 02:17  小節とか拍をフレーム・サンプルの位置と対応付けるスクリプト - にわかな奴の砂場 を含むブックマーク はてなブックマーク -  小節とか拍をフレーム・サンプルの位置と対応付けるスクリプト - にわかな奴の砂場

これは何?

音や動画を編集してると「あの小節の先頭って何フレーム目だっけ?」とか「サビのとこだけ抜いてループさせたいんだけどキレイに切れないなあ……」なんて思った事があった訳でして、そういう時に自分用に書いてみたものです。

……なんですが、動画については先駆者がいらっしゃいます。ので僭越ながら御紹介。

考え方

bpmと言うのは1分当たりの拍数なので、1拍の長さは1分をbpmで割ったものです。bpmが180なら1拍の長さは約0.333秒となります。また動画や音声は1秒当たり何サンプル(サンプリングレートとか言う)、という記録のされ方なので、60倍すれば1分分になります。30fpsの動画なら1分で1800サンプルになります。

1分=1800サンプルと表せると言う事は、1拍当たりのサンプル数は「サンプリングレート×60÷bpm」と言う事になりまして、この「1拍当たりのサンプル数」を足していけば、拍や小節の切れ目が何サンプル目なのか判りやすいんじゃね? と言うのが元にあります。

曲シンクロ的な意味も含めて、以下が大変参考になります。とりあえず読むべき。

使用上の注意

  • 御利用は自己責任でお願いします。改造は御自由に。転載は引用元を明記の上。笑
  • 1拍の長さはActivePerlが返してくるものをそのまま突っ込んでるので誤差は無視できる程度には小さくなってると思いますが、長尺(5分以上)のものでは試した事が無いので判りません。
  • 同期が取れなくても泣かない。

出力サンプル

左から順に、小節番号,小節開始時刻.サンプル,各拍開始サンプルです。

1小節の長さは「或る小節開始サンプル」から「次の小節開始サンプル-1」です。

C:hide$ana.pl -b 170 -c -r 30 -m 10 -t 8/8
tempo = 8/8
bpm = 340
sampling rate = 30
offset = 0
samples/beat = 5.29411764705882
samples/bar = 42.3529411764706

1       0:00.00         0:00.00 0:00.05 0:00.10 0:00.15 0:00.21 0:00.26 0:01.01 0:01.07
2       0:01.12         0:01.12 0:01.17 0:01.22 0:01.28 0:02.03 0:02.08 0:02.14 0:02.19
3       0:02.24         0:02.24 0:03.00 0:03.05 0:03.10 0:03.15 0:03.21 0:03.26 0:04.01
4       0:04.07         0:04.07 0:04.12 0:04.17 0:04.22 0:04.28 0:05.03 0:05.08 0:05.14
5       0:05.19         0:05.19 0:05.24 0:05.29 0:06.05 0:06.10 0:06.15 0:06.21 0:06.26
6       0:07.01         0:07.01 0:07.07 0:07.12 0:07.17 0:07.22 0:07.28 0:08.03 0:08.08
7       0:08.14         0:08.14 0:08.19 0:08.24 0:08.29 0:09.05 0:09.10 0:09.15 0:09.21
8       0:09.26         0:09.26 0:10.01 0:10.07 0:10.12 0:10.17 0:10.22 0:10.28 0:11.03
9       0:11.08         0:11.08 0:11.14 0:11.19 0:11.24 0:12.00 0:12.05 0:12.10 0:12.15
10      0:12.21         0:12.21 0:12.26 0:13.01 0:13.07 0:13.12 0:13.17 0:13.22 0:13.28

使い方(コマンド的な意味で

まずPerlの実行環境が必要です。適当にインストールしてください。

次に下のソースを適当に保存してCLI(Windowsならcmd.exeとか)で実行してください。オプションは以下があります。「数字」とある所に入れる数字は全て半角で。

-b 数字
bpmを指定します(少数可)。デフォルトは120。
-c
時間.余りサンプル で表示します。
-l 数字
サンプル数表示部の文字数を指定します。元々表示が崩れるのを嫌って付けたものでしたが、無駄機能化しています。デフォルトは15。
-m 数字
表示する最大小節行数を指定します。デフォルトは20。
-o 数字
開始オフセットサンプル数を指定します。デフォルトは0。
-r 数字
サンプリングレートを指定します(少数可)。デフォルトは44100。
-t m/n
曲のテンポを3/4のように、m/n形式で指定します。7/8とか13/16とかも処理できますが、あまり検証していません。デフォルトは4/4。

使い方(実践的な意味で

そのうち書く。

想定問答集

Excelとかで読める?
タブ区切りテキストとして読み込めばOKかもしれません。
何かずれてるんだけど?
オフセット指定か、或いはbpmが誤っています。執念で何とかしてください。
GUI無いの?
俺需要が無いのでありません。作る予定もありません(;´Д`)
shbang変じゃね?
ドザだから。

ソース

長いので折ります。へぼPerlerなので色々とボロいので注意。

#!c:/perl/bin/perl

use strict;
use warnings;

sub Padder;
sub Sample2Time;

my %sample;
my $chrono;

# default
my $bar_max = 20;
my $bpm     = 120;
my $maxlength = 15;
my $tempo = '4/4';
$sample{'offset'} = 0;
$sample{'rate'}   = 44100;

# set option
my $i;
for ($i=0; $i<=$#ARGV; $i++) {
	if    ("$ARGV[$i]" eq '-b') {$i++; $bpm       = $ARGV[$i]; chomp $bpm;}
	elsif ("$ARGV[$i]" eq '-c') {$chrono = 1;}
	elsif ("$ARGV[$i]" eq '-l') {$i++; $maxlength = int $ARGV[$i]; chomp $maxlength;}
	elsif ("$ARGV[$i]" eq '-m') {$i++; $bar_max   = int $ARGV[$i]; chomp $bar_max;}
	elsif ("$ARGV[$i]" eq '-o') {$i++; $sample{'offset'} = int $ARGV[$i]; chomp $sample{'offset'};}
	elsif ("$ARGV[$i]" eq '-r') {$i++; $sample{'rate'}   = $ARGV[$i]; chomp $sample{'rate'};}
	elsif ("$ARGV[$i]" eq '-t') {$i++; $tempo     = $ARGV[$i]; chomp $tempo;}
	else {die "invalid option:$ARGV[$i]\n";}
}

(my $beat, my $div) = split /\//, $tempo;
$bpm *= $div / 4;

$sample{'sum'} = $sample{'offset'};
$sample{'per_minute'} = $sample{'rate'} * 60;
$sample{'per_beat'} = $sample{'per_minute'} / $bpm;
$sample{'per_bar'} = $sample{'per_beat'} * $beat;

# print setting
print "tempo = ",$tempo,"\n";
print "bpm = ",$bpm,"\n";
print "sampling rate = ",$sample{'rate'},"\n";
print "offset = ",$sample{'offset'},"\n";
print "samples/beat = ",$sample{'per_beat'},"\n";
print "samples/bar = ",$sample{'per_bar'},"\n";
print "\n";

# print list
my $bar;
foreach $bar (1 .. $bar_max) {
	#print &Padder($bar, length $bar_max, 'space'),"\t";
	print $bar,"\t";
	print &Sample2Time(\%sample),"\t";

	foreach $i (1 .. $beat) {
		if ($chrono) {print "\t",&Sample2Time(\%sample);}
		else {print "\t",&Padder($sample{'sum'}, $maxlength, 'space');}
		$sample{'sum'} += $sample{'per_beat'};
	}
	print "\n";
}

exit 0;
# end main

# subroutine
sub Sample2Time {
	my $s = shift;
	my $totalsec = $s->{'sum'} / $s->{'rate'};
	my $min = int $totalsec / 60;
	my $sec = &Padder($totalsec % 60, 2, 'zero');
	my $mod = &Padder($s->{'sum'} % $s->{'rate'}, 2, 'zero');
	my $res = "$min" . ':' . "$sec" . '.' . "$mod";
	return $res;
}

sub Padder {
	my $s       = shift;
	my $maxlen  = shift;
	my $padchar = ' ';
	if ("$_[0]" eq 'zero') {$padchar = '0';}
	my $int = int($s + 0.5);

	my $strlen = length $int;
	if ($strlen < $maxlen) {
		my $padding;
		my $d = $maxlen - $strlen;
		foreach (1 .. $d) {$padding .= "$padchar";}
		$s = "$padding" . "$int";
	} else {
		$s = $int;
	}
	return $s;
}

__END__

[] やよい特集 02:17  やよい特集 - にわかな奴の砂場 を含むブックマーク はてなブックマーク -  やよい特集 - にわかな奴の砂場

拙作を取り上げて頂いてしまいました。ありがとうございます(_o_)

って言うか周り凄すぎて俺涙目なんですけどorz 精進します……

やよいと言えば 02:17 やよいと言えば - にわかな奴の砂場 を含むブックマーク はてなブックマーク - やよいと言えば - にわかな奴の砂場

昨日近所のやよい軒で晩飯食ってたんですが、店内BGMで『G線上のアリア』が流れてたんですよ。

ただ直ぐに曲名出てこなくて「あれ何だっけこの曲……」なんて思ってたんですが、何か閃いたわけですよ。

アイドルマスター Rori Classic (?G線上の紳士?) by カワイソ(´・ω・) ス -ニコニコ動画』が。

……俺ももうダメだと思った。

[] NicoCacheについて 02:17  NicoCacheについて - にわかな奴の砂場 を含むブックマーク はてなブックマーク -  NicoCacheについて - にわかな奴の砂場