ボイスレコーダーで 2 時間とか録音したのはいいけど、これどうやってテキストデータにするの?という事態が勃発しました。キーボードにシーク動作とか割り当てて、自動リピートとかあれば便利だなぁと思い、perl で書いてみました。
Alt + Tab で他のウィンドと行き来したあとで、全くキーを受け取らなくなる現象があってハマリました。GetEvents で入力があるか確認してから Input で入力内容を得るとハマらずに済みます。シーク時に Win32::MediaPlayer まわりに与える時間は ms に直して渡しました。
「テープ起こし」に関するブックマークコメントより - blog.woremacx.com について関連エントリを書きました
今回のスクリプトのコンセプト
- 自動的に A-B リピートになる
- 4 種類の移動量でシークできる
- perl で書いてあるため、perl の環境さえ入っていれば容易に改造できる
使い方
開くファイルをスクリプトの引数として起動します。起動したら、勝手に 10 秒リピートになっています。
- q: 終了
- 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); # my $mode = $console->Mode(); # print "ENABLE_LINE_INPUT\n" if $mode & ENABLE_LINE_INPUT; # print "ENABLE_ECHO_INPUT\n" if $mode & ENABLE_ECHO_INPUT; # print "ENABLE_PROCESSED_INPUT\n" if $mode & ENABLE_PROCESSED_INPUT; # print "ENABLE_WINDOW_INPUT\n" if $mode & ENABLE_WINDOW_INPUT; while (1) { while ($console->GetEvents) { my @event = $console->Input; # 0: event type: 1 for keyboard # 1: key down: TRUE if the key is being pressed, FALSE if the key is being released # 2: repeat count: the number of times the key is being held down # 3: virtual keycode: the virtual key code of the key # 4: virtual scancode: the virtual scan code of the key # 5: char: the ASCII code of the character (if the key is a character key, 0 otherwise) # 6: control key state: the state of the control keys (SHIFTs, CTRLs, ALTs, etc.) 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; }
売り上げランキング: 283

いろいろ使えます。
ライブの録音・再生に大活躍売り上げランキング: 1822

音楽用にも
買うならコレ
値段にはわけがある
クリアーな音質です


Leave a comment