ボイスレコーダーで 2 時間とか録音したのはいいけど、これどうやってテキストデータにするの?という事態が勃発しました。キーボードにシーク動作とか割り当てて、自動リピートとかあれば便利だなぁと思い、perl で書いてみました。
Alt + Tab で他のウィンドと行き来したあとで、全くキーを受け取らなくなる現象があってハマリました。GetEvents で入力があるか確認してから Input で入力内容を得るとハマらずに済みます。シーク時に Win32::MediaPlayer まわりに与える時間は ms に直して渡しました。
「テープ起こし」に関するブックマークコメントより - blog.woremacx.com について関連エントリを書きました
今回のスクリプトのコンセプト
- 自動的に A-B リピートになる
- 4 種類の移動量でシークできる
- perl で書いてあるため、perl の環境さえ入っていれば容易に改造できる
使い方
開くファイルをスクリプトの引数として起動します。起動したら、勝手に 10 秒リピートになっています。
- j: 5 秒後
- k: 10 秒後
- l: 30 秒後
- ;: 5 分後
- f: 5 秒前
- d: 10 秒前
- s: 30 秒前
- a: 5 分前
- t: リピートするかのトグル
- u: リピート秒数--
- i: リピート秒数++
コード
coderepos にもうpしました repeat-audio-player.pl
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
use Win32::Console;
use Win32::MediaPlayer;
use Time::HiRes ();
sub keywatcher {
my ($queue) = shift;
my $console = new Win32::Console(STD_INPUT_HANDLE);
$console->Mode(ENABLE_PROCESSED_INPUT);
while (1) {
while ($console->GetEvents) {
my @event = $console->Input;
next unless $event[1];
my $c = lc(chr($event[5]));
$queue->enqueue($c);
return 0 if $c eq 'q';
}
}
return 0;
}
sub worker {
my ($queue, $file) = @_;
my $wp = Win32::MediaPlayer->new;
$wp->load($file) or die;
$wp->play;
my $state = {
mute => 0,
playing => 1,
pos => 0,
len => res_to_sec($wp->length(0)),
base => 0,
repeat => 1,
repeat_dur => 10,
};
my %keymap = (
j => 5,
k => 10,
l => 30,
';' => 300,
f => -5,
d => -10,
s => -30,
a => -300,
);
printf "repeats each %d secs\n", $state->{repeat_dur};
my $console = new Win32::Console(STD_OUTPUT_HANDLE);
my $seek = 0;
while (1) {
$state->{len} = res_to_sec($wp->length(0));
$state->{pos} = res_to_sec($wp->pos(0));
if ($seek) {
$wp->pause;
$wp->seek($state->{base} * 1000);
$wp->resume;
$seek = 0;
next;
}
my $buf = sprintf "%s / %s\r", sec_to_hms($state->{pos}), sec_to_hms($state->{len});
$console->Write($buf);
Time::HiRes::sleep(0.5);
my $repeat_state = sub {
printf "\n";
printf "repeat %s\n", $state->{repeat} ? "on" : "off";
printf "repeats each %d secs\n", $state->{repeat_dur} if $state->{repeat};
};
if ($state->{repeat} &&
$state->{pos} >= ($state->{base} + $state->{repeat_dur})) {
$seek++;
}
while ($queue->pending) {
my $c = $queue->dequeue;
if (defined($keymap{$c})) {
unless ($state->{repeat}) {
$state->{base} = $state->{pos};
}
$state->{base} += $keymap{$c};
$seek++;
} elsif ($c eq 't') {
$state->{repeat} = $state->{repeat} ? 0 : 1;
$repeat_state->();
} elsif ($c eq 'r') {
$repeat_state->();
} elsif ($c eq 'u') {
$state->{repeat_dur}--;
$state->{repeat_dur} = 1 if $state->{repeat_dur} < 1;
$repeat_state->();
} elsif ($c eq 'i') {
$state->{repeat_dur}++;
$repeat_state->();
} elsif ($c eq 'p') {
$seek++;
}
return 0 if $c eq 'q';
}
}
return 0;
}
sub main {
my $file = shift(@ARGV);
die unless $file;
my $queue = new Thread::Queue;
my $t1 = threads->new(\&keywatcher, $queue);
my $t2 = threads->new(\&worker, $queue, $file);
$t1->join;
$t2->join;
print "done.\n";
}
main;
sub res_to_sec {
my $param = shift;
return int($param/1000);
}
sub res_to_hms {
my $param = shift;
return sec_to_hms(res_to_sec($param));
}
sub sec_to_hms {
my $total = shift;
my $sec = $total % 60;
my $min = ($total - $sec) / 60;
my $hour = int($min / 60);
$min = $min % 60;
return sprintf "%02d:%02d:%02d", $hour, $min, $sec;
}
sub sec_to_ms {
my $total = shift;
my $sec = $total % 60;
my $min = ($total - $sec) / 60;
return sprintf "%02d:%02d", $min, $sec;
}
オリンパス (2007-03-23)
売り上げランキング: 283
おすすめ度の平均:


いろいろ使えます。

ライブの録音・再生に大活躍
オリンパス (2007-09-14)
売り上げランキング: 1822
おすすめ度の平均:


音楽用にも

買うならコレ

値段にはわけがある

クリアーな音質です
Recent Comments