diff -urbN freepwing-1.4.3.orig/fpwutils/FPWUtils.pm freepwing-1.4.3/fpwutils/FPWUtils.pm --- freepwing-1.4.3.orig/fpwutils/FPWUtils.pm 2001-06-30 13:46:00.000000000 +0900 +++ freepwing-1.4.3/fpwutils/FPWUtils.pm 2005-02-13 03:15:47.526214400 +0900 @@ -50,6 +50,7 @@ $color_graphic_tag_file_name $sound_file_name $sound_tag_file_name + $sound_fmt_file_name $honmon_file_name $half_char_name_file_name $full_char_name_file_name @@ -93,6 +94,7 @@ $color_graphic_tag_file_name $sound_file_name $sound_tag_file_name + $sound_fmt_file_name $honmon_file_name $half_char_name_file_name $full_char_name_file_name @@ -199,6 +201,9 @@ # 音声タグファイル名 $sound_tag_file_name = "$work_directory/sndtag"; + # 音声形式ファイル名 (satomii) + $sound_fmt_file_name = "$work_directory/sndfmt"; + # HONMON ファイル名 $honmon_file_name = "honmon"; diff -urbN freepwing-1.4.3.orig/fpwutils/Menu.pm freepwing-1.4.3/fpwutils/Menu.pm --- freepwing-1.4.3.orig/fpwutils/Menu.pm 2000-10-20 22:38:57.000000000 +0900 +++ freepwing-1.4.3/fpwutils/Menu.pm 2005-02-13 08:51:48.045617600 +0900 @@ -75,6 +75,14 @@ return 0; } + # + # 音声形式ファイルを読み込む。(satomii) + # + if (-f $sound_fmt_file_name + && !$self->set_sounds_in_file($sound_fmt_file_name)) { + return 0; + } + return 1; } diff -urbN freepwing-1.4.3.orig/fpwutils/Sound.pm freepwing-1.4.3/fpwutils/Sound.pm --- freepwing-1.4.3.orig/fpwutils/Sound.pm 2001-06-29 17:25:48.000000000 +0900 +++ freepwing-1.4.3/fpwutils/Sound.pm 2005-02-13 08:14:45.890315200 +0900 @@ -58,7 +58,9 @@ sub open { my $self = shift; - if (!$self->SUPER::open($suond_file_name, $sound_tag_file_name)) { + if (!$self->SUPER::open($sound_file_name, + $sound_tag_file_name, + $sound_fmt_file_name)) { return 0; } diff -urbN freepwing-1.4.3.orig/fpwutils/Text.pm freepwing-1.4.3/fpwutils/Text.pm --- freepwing-1.4.3.orig/fpwutils/Text.pm 2000-10-20 22:38:57.000000000 +0900 +++ freepwing-1.4.3/fpwutils/Text.pm 2005-02-13 03:22:11.217936000 +0900 @@ -75,6 +75,14 @@ return 0; } + # + # 音声形式ファイルを読み込む。(satomii) + # + if (-f $sound_fmt_file_name + && !$self->set_sounds_in_file($sound_fmt_file_name)) { + return 0; + } + return 1; } diff -urbN freepwing-1.4.3.orig/fpwutils/fpwsound freepwing-1.4.3/fpwutils/fpwsound --- freepwing-1.4.3.orig/fpwutils/fpwsound 2002-12-01 21:32:51.650776000 +0900 +++ freepwing-1.4.3/fpwutils/fpwsound 2005-02-13 08:14:18.140412800 +0900 @@ -37,13 +37,16 @@ # unlink($sound_file_name); unlink($sound_tag_file_name); +unlink($sound_fmt_file_name); $sound = FreePWING::Sound->new(); # # 生成側ファイルを開く。 # -if (!$sound->open($sound_file_name, $sound_tag_file_name)) { +if (!$sound->open($sound_file_name, + $sound_tag_file_name, + $sound_fmt_file_name)) { die "$PROGRAM_NAME: " . $sound->error_message() . "\n"; } diff -urbN freepwing-1.4.3.orig/src/BaseText.pm freepwing-1.4.3/src/BaseText.pm --- freepwing-1.4.3.orig/src/BaseText.pm 2001-08-21 16:19:20.000000000 +0900 +++ freepwing-1.4.3/src/BaseText.pm 2005-02-13 09:01:35.470292800 +0900 @@ -25,6 +25,7 @@ use FreePWING::Reference; use FreePWING::Tag; use FreePWING::RefUserChar; +use FreePWING::RefSound; use FreePWING::CharConv; use strict; use integer; @@ -105,6 +106,9 @@ # 全角外字の定義情報 'full_user_characters' => FreePWING::RefUserChar->new(), + # 音声形式情報 (satomii) + 'sounds' => FreePWING::RefSound->new(), + # エラーメッセージ 'error_message' => '', }; @@ -292,6 +296,32 @@ # # 書式: +# set_sounds_in_file(file_name) +# file_name +# 音声形式ファイルの名前。 +# メソッドの区分: +# public インスタンスメソッド。 +# 説明: +# 音声形式ファイルを読み込む。 +# 戻り値: +# 成功すれば 1 を返す。失敗すれば 0 を返す。 +# +# (satomii) +# +sub set_sounds_in_file { + my $self = shift; + my ($file_name) = @ARG; + + if (!$self->{'sounds'}->add_sounds_in_file($file_name)) { + $self->{'error_message'} = $self->{'sounds'}->error_message(); + $self->close_internal(); + return 0; + } + return 1; +} + +# +# 書式: # write_data(data) # data # 書き込むデータ (文字列)。 @@ -934,15 +964,26 @@ # # 音声参照 +# 音声データの名前を引数で指定。 # sub add_sound_start { my $self = shift; my ($sound_name) = @ARG; - if (!$self->add_modifier_start('sound', - pack('n3N3', 0x1f4a, 0, 0x0112, 0, 0, 0))) { + # 音声形式は FreePWING::RefSound 経由で取得する。(satomii) + if (!$self->add_modifier_start( + 'sound', + pack('nC2nNnNn', 0x1f4a, 0, + $self->{'sounds'}->sound_type($sound_name), + $self->{'sounds'}->sound_format($sound_name), + 0, 0, 0, 0))) { return 0; } + + # if (!$self->add_modifier_start('sound', + # pack('n3N3', 0x1f4a, 0, 0x0012, 0, 0, 0))) { + # return 0; + # } if (!$self->{'reference'} ->add_tag_entry($self->{'position'} - 12, "sound:$sound_name")) { $self->{'error_message'} = $self->{'reference'}->error_message(); diff -urbN freepwing-1.4.3.orig/src/RefSound.pm freepwing-1.4.3/src/RefSound.pm --- freepwing-1.4.3.orig/src/RefSound.pm 1970-01-01 09:00:00.000000000 +0900 +++ freepwing-1.4.3/src/RefSound.pm 2005-02-13 08:52:52.618468800 +0900 @@ -0,0 +1,140 @@ +# -*- Perl -*- +# Copyright (c) 2000 Motoyuki Kasahara +# Copyright (c) 2005 Satomi I. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# +# 音声形式ファイルを参照する。 +# +package FreePWING::RefSound; + +require 5.005; +require Exporter; +use English; +use FileHandle; +use strict; +use integer; + +use vars qw(@ISA + @EXPORT + @EXPORT_OK); + +@ISA = qw(Exporter); + +# +# 書式: +# new() +# メソッドの区分: +# public クラスメソッド。 +# 説明: +# 新しいオブジェクトを作る。 +# 戻り値: +# 作成したオブジェクトへのリファレンスを返す。 +# +sub new { + my $type = shift; + my $new = { + 'format' => {}, + 'error_message' => '', + }; + return bless($new, $type); +} + +# +# 書式: +# add_sounds_in_file(file_name) +# file_name +# 読み込む音声形式ファイルの名前。 +# メソッドの区分: +# public インスタンスメソッド。 +# 説明: +# 音声形式ファイルを読み込む。 +# 戻り値: +# 成功すれば 1 を返す。失敗すれば 0 を返す。 +# +sub add_sounds_in_file { + my $self = shift; + my ($file_name) = @ARG; + + # + # ファイルを開く。 + # + my $handle = FileHandle->new(); + if (!$handle->open($file_name, 'r')) { + $self->{'error_message'} = + "failed to open the file, $ERRNO: $file_name"; + return 0; + } + + # + # 各行を読み込んでハッシュに格納する。 + # + my ($line, @fields); + + while (1) { + $line = $handle->getline(); + last if (!defined($line)); + chomp($line); + + @fields = split(/\t/, $line); + if (defined($self->{'sounds'}->{$fields[0]})) { + $self->{'error_message'} = + "redefined sound name, $fields[0]: line $NR, $file_name"; + $self->close(); + return 0; + } + + $self->{'sounds'}->{$fields[0]} = [ map(hex, splice(@fields, 1)) ]; + } + + # + # ファイルを閉じる。 + # + $handle->close(); + 1; +} + +###################################################################### +# <インスタンス変数の値を返すメソッド群> +# +# 書式: +# インスタンス変数名() +# メソッドの区分: +# public インスタンスメソッド。 +# 戻り値: +# インスタンス変数の値を返す。 +# +sub sound_type { + my $self = shift; + my ($tag) = @ARG; + + if (defined($self->{'sounds'}->{$tag})) { + $self->{'sounds'}->{$tag}[0]; + } +} + +sub sound_format { + my $self = shift; + my ($tag) = @ARG; + + if (defined($self->{'sounds'}->{$tag})) { + $self->{'sounds'}->{$tag}[1]; + } +} + +sub error_message { + my $self = shift; + $self->{'error_message'}; +} + +1; diff -urbN freepwing-1.4.3.orig/src/Sound.pm freepwing-1.4.3/src/Sound.pm --- freepwing-1.4.3.orig/src/Sound.pm 2001-08-21 16:29:48.000000000 +0900 +++ freepwing-1.4.3/src/Sound.pm 2005-02-13 09:39:40.105436800 +0900 @@ -66,6 +66,13 @@ # タグ 'tag' => FreePWING::Tag->new(), + # 終了タグ (satomii) + 'end_tag_prefix' => 'sound-end', + + # 音声形式ファイル (satomii) + 'fmt_file_name' => '', + 'fmt_handle' => FileHandle->new(), + # エラーメッセージ 'error_message' => '', }; @@ -74,11 +81,13 @@ # # 書式: -# open(file_name, [tag_file_name]) +# open(file_name, [tag_file_name, [fmt_file_name]]) # file_name # テキストファイルの名前。 # tag_file_name # タグファイルの名前。 +# fmt_file_name +# 音声形式ファイルの名前。 # メソッドの区分: # public インスタンスメソッド。 # 説明: @@ -88,7 +97,7 @@ # sub open { my $self = shift; - my ($file_name, $tag_file_name) = @ARG; + my ($file_name, $tag_file_name, $fmt_file_name) = @ARG; # # ファイルを開く。 @@ -112,6 +121,19 @@ return 0; } + # + # 音声形式ファイルを開く。(satomii) + # + if (defined($fmt_file_name)) { + $self->{'fmt_file_name'} = $fmt_file_name; + if (!$self->{'fmt_handle'}->open($fmt_file_name, 'w')) { + $self->{'error_message'} = + "failed to open the file, $ERRNO: $fmt_file_name"; + $self->close_internal(); + return 0; + } + } + return 1; } @@ -167,6 +189,13 @@ $self->{'handle'}->close(); } $self->{'tag'}->close_internal(); + + # + # 音声形式ファイルが開かれていれば閉じる。(satomii) + # + if ($self->{'fmt_handle'}->fileno()) { + $self->{'fmt_handle'}->close(); + } } # @@ -211,14 +240,155 @@ binmode($handle); # - # 指定されたファイルを読み込んで、バイナリファイルに書き込む。 + # 指定されたファイルの形式を調べて work/sndfmt に記録する。(satomii) # my ($data, $data_length); + + $data_length = $handle->read($data, 8); + if ($data_length != 8) { + $self->{'error_message'} = (!defined($data_length)) ? + "failed to read the file, $ERRNO: $file_name" : + "unknown sound format: $file_name"; + $self->close_internal(); + return 0; + } + + if (substr($data, 0, 4) eq 'RIFF') { + # + # WAVE ファイル + # + $data_length = $handle->read($data, 4); + if ($data_length != 4) { + $self->{'error_message'} = (!defined($data_length)) ? + "failed to read the file, $ERRNO: $file_name" : + "invalid RIFF data: $file_name"; + $self->close_internal(); + return 0; + } elsif ($data ne 'WAVE') { + $self->{'error_message'} = + "unknown RIFF type, $data: $file_name"; + $self->close_internal(); + return 0; + } + + if ($self->{'fmt_handle'}->fileno()) { + my $header_position = $handle->tell(); + my ($chunk_code, $chunk_length); + + # + # fmt チャンクを探す。 + # + while (1) { + $data_length = $handle->read($data, 8); + if ($data_length != 8) { + $self->{'error_message'} = do { + if (!defined($data_length)) { + "failed to read the file, $ERRNO: $file_name"; + } elsif ($data_length == 0) { + "unexpected end of file: $file_name"; + } else { + "invalid WAVE data: $file_name"; + } + }; + $self->close_internal(); + return 0; + } + + $chunk_code = substr($data, 0, 4); + $chunk_length = unpack('L', substr($data, 4)); + + $data_length = $handle->read($data, $chunk_length); + if ($data_length != $chunk_length) { + $self->{'error_message'} = (!defined($data_length)) ? + "failed to read the file, $ERRNO: $file_name" : + "failed to read the $chunk_code chunk: $file_name"; + $self->close_internal(); + return 0; + } + + if ($chunk_code ne 'fmt ') { + next; + } elsif ($chunk_length < 16) { + $self->{'error_message'} = + "invalid fmt chunk: $file_name"; + $self->close_internal(); + return 0; + } + + # + # チャンネル数、サンプリング周波数、ビット長を取得する。 + # + my @fmt = unpack('S2L2S2', $data); + if (!$self->{'fmt_handle'}->printf( + "%s\t01\t%d0%d%d\n", + $tag, + ($fmt[1] == 2) ? 1 : 0, + ($fmt[5] == 16) ? 0 : 1, + ($fmt[2] == 441000) ? 0 : + ($fmt[2] == 220500) ? 1 : 2)) { + $self->{'error_message'} = + "failed to write the file, $ERRNO: " + . $self->{'fmt_file_name'}; + $self->close_internal(); + return 0; + } + last; + } + + # + # 読み出し位置を最初のサブチャンクの先頭に戻す。 + # + if (!$handle->seek($header_position, 0)) { + $self->{'error_message'} = + "failed to seek the file, $ERRNO: $file_name"; + $self->close_internal(); + return 0; + } + } + + } elsif ($data eq "MThd\x00\x00\x00\x06") { + # + # MIDI ファイル (SMF) + # + if ($self->{'fmt_handle'}->fileno()) { + if (!$self->{'fmt_handle'}->print("$tag\t02\t0000\n")) { + $self->{'error_message'} = + "failed to write the file, $ERRNO: " + . $self->{'fmt_file_name'}; + $self->close_internal(); + return 0; + } + } + + # + # 読み出し位置を先頭に戻す。 + # または最初のトラックチャンクの先頭にするべき? MIDI に対応したソフトが + # ないためテストできず。JIS X 4081 の仕様書をお持ちの方、適当に修正して + # ください。 + # + if (!$handle->seek(0, 0)) { + $self->{'error_message'} = + "failed to seek the file, $ERRNO: $file_name"; + $self->close_internal(); + return 0; + } + + } else { + $self->{'error_message'} = "unknown sound format: $file_name"; + $self->close_internal(); + return 0; + } + + # + # 音声データを読み込んでバイナリファイルに書き込む。 + # + my $start_position = $self->{'position'}; + for (;;) { $data_length = $handle->read($data, $block_length); if (!defined($data_length)) { $self->{'error_message'} = - "failed to read the file, $ERRNO: " . $file_name; + "failed to read the file, $ERRNO: $file_name"; $self->close_internal(); return 0; } elsif ($data_length == 0) { @@ -230,7 +400,6 @@ $self->close_internal(); return 0; } - $self->{'position'} += $data_length; } @@ -245,7 +414,7 @@ # if (defined($self->{'end_tag_prefix'})) { my ($end_tag) = $self->{'end_tag_prefix'} . ':' . $tag; - my ($end_position) = $self-{'position'} - 1; + my ($end_position) = $self->{'position'} - 1; if ($end_position < $start_position) { $end_position = $start_position; }