以下、本発明の実施の形態について、図面を参照しながら詳細に説明する。
図1は、本実施の形態による運指情報生成装置を搭載した電子楽器の構成を説明する図である。
その電子楽器は、図1に示すように、楽器全体の制御を行うCPU1と、そのCPU1が実行するプログラムや各種制御用データを格納したROM2と、CPU1がワークに用いるRAM3と、各種スイッチ等の操作子を有する入力部4と、例えば液晶表示装置である表示部5と、各種データの格納に用いることができる外部記憶装置6と、演奏操作の対象となる演奏操作子群である鍵盤7と、CPU1の指示に従って楽音を発音させるサウンドシステム8と、を備えている。
なお、上記外部記憶装置6は、例えば着脱自在な記録媒体にアクセスするものである。入力部4に備えられた運指情報の生成に係わる操作子としては、運指情報生成の対象となる曲(演奏情報)を指定するための曲指定スイッチ、運指情報の生成を指示するための運指生成スイッチ、運指情報生成の動作モードを設定するためのモード設定スイッチ、その動作モードとして、指定区間(範囲)のみ運指情報を生成対象とするモード(以降「指定区間モード」と呼ぶ)が設定されている場合に、その区間を設定するための範囲設定スイッチ、指定区間の前、或いは後を考慮する生成を行うか否か設定するためのオプション設定スイッチ、及び内容が同一のフレーズを考慮した補正を行うか否か設定するための同一フレーズ補正スイッチ、などが設けられている。
運指情報生成の対象となる演奏データ(情報)は、例えば曲指定スイッチを操作して、外部記憶装置6がアクセス可能なもののなかから選択するようになっている。CPU1は、ユーザが選択した演奏データを外部記憶装置6に読み出させ、それをRAM3に格納する。
図2は運指情報生成のためにRAM3に格納される各種データの構成を説明する図である。図2(a)は演奏データの構成、図2(b)は制御変数をそれぞれ示している。
図2(a)に括弧を付して表記の「ME」は、曲を構成する1音符に係わるデータ(音符データ)を表している。その音符データMEは、「time」と表記の発音開始時刻、「gate」と表記の発音継続時間、「pitch」と表記の発音ピッチ(ノート番号)、「posx」と表記の発音ピッチに対応する鍵の鍵盤座標、「tend」と表記のピッチ増減傾向、「fig」と表記の運指番号(その鍵の押鍵に使うべき指を示す番号)、「cost」と表記の運指コスト(その鍵を押鍵するうえでの難易度)、「pid」と表記のフレーズ番号(その発音ピッチの音符が属するフレーズに割り当てられる識別用番号)、及び「pstat」と表記のフレーズ状態(その音符が属するフレーズ内での位置)、の各データから構成されている。
図示していないデータとしては、鍵の押鍵に使うべき指が右手か否かを示すパートや、その押鍵時の強さを示すベロシティなども存在する。しかし、ここでは説明上、便宜的に省略している。
データposxは、MIDIフォーマットで60のノート番号が割り当てられた鍵を基準(0)として、白鍵毎に2つずつ変化させる値で鍵盤座標を表現したものである。そのように変化させることにより、白鍵は偶数、黒鍵は奇数とさせている。これは、白鍵と黒鍵とでは鍵盤7の長手方向の交差方向上の位置に違いがあるからである。
上記ピッチ増減傾向は、その増減の切り替わる点に当たる音符では0、前の音符と同じピッチ(音高)の音符では±1、前の音符のピッチと異なる音符では±2、で表現するようにしている。その符号は+はピッチが増加中であることを示し、「−」はピッチが減少中であることを示している。
上記運指番号としては、親指は0、人指し指は1,中指は2、薬指は3、小指は4をそれぞれ割り当てている。上記フレーズ状態としては、フレーズ先頭位置の音符には0、フレーズ終了位置の音符には2、それ以外、つまりその間の音符には1、をそれぞれ割り当てている。
上記time、gate、及びpitchは、外部記憶装置6から読み出された演奏データを構成するデータか、或いはそのデータから生成されるものである。それら以外のデータは、運指情報を構成するデータ、或いはそのデータ生成に用いるデータである。
一方、制御変数としては、図2(b)に示すように、「ev_max」と表記の全音符数−1の値(演奏データ最大インデックス)、「mode」と表記の動作モードを示す値、「ev_s」と表記の指定区間先頭インデックス、「ev_e」と表記の指定区間末端インデックス、「lookupb」と表記の指定区間前考慮フラグ、「lookupf」と表記の指定区間後考慮フラグ、「me_s」と表記の指定区間前を考慮する場合の指定区間先頭インデックス、「me_eと表記の指定区間後を考慮する場合の指定区間末端インデックス、「me_top」と表記の処理区間先頭インデックス、「me_tail」と表記の処理区間末端インデックス、「loopcnt」と表記の処理ループカウンタ、及び「phrcor」と表記の同一フレーズ補正実行フラグ、の代入用の変数が用意される。
上記modeの値としては、上記指定区間モードの設定時には1、演奏データ全体を運指情報の生成の対象にするモード(以降「全体モード」と呼ぶ)の設定時には0、が代入される。上記lookupb、lookupfの各値としては、指定区間を越える範囲を考慮する場合には1、そうでない場合には0がそれぞれ代入される。上記phrcorとしても同様に、同一内容のフレーズを対象にした補正を行う場合には1、そうでない場合には0が代入される。上記ev_s、ev_e、lookupb、lookupf、及びphrcorとしては、ユーザの設定に応じた値が代入される。
以降は、図3〜図8、図10〜図14、図16〜図21、及び図23〜図29に示す各種処理のフローチャート、並びに図9、図15、及び図22に示す各種説明図を参照しつつ、電子楽器の動作について詳細に説明する。なお、それらの図に示す各処理は、CPU1がROM2に格納されたプログラムを実行することで実現される。
図3は、全体処理のフローチャートである。始めに図3を参照して、全体処理について詳細に説明する。
電源がオンされると、先ず、ステップSA1で初期処理を実行し、電子楽器を所定の状態に設定する。続くステップSA2では、曲指定スイッチがオンしたか否か判定する。そのスイッチをユーザが操作したことで入力部4からその旨を示す信号を受け取った場合、判定はYESとなり、次にステップSA3において、ユーザの入力部4への操作により指定される曲(演奏データ)を外部記憶装置6から取り込むための処理を実行してからステップSA4に移行する。演奏データの取り込みを行う際、音符データMEの個数をカウントして、そのカウント値−1の値を変数ev_maxに代入する。一方、そうでない場合には、判定はNOとなり、次にそのステップSA4の処理を実行する。
ステップSA4では、ステップSA3で取り込まれる演奏データのなかで運指情報の生成の対象となる範囲をユーザに設定させるための範囲設定処理を実行する。次のステップSA5では、運指生成スイッチがオンしたか否か判定する。そのスイッチをユーザが操作した場合、判定はYESとなり、次にステップSA6で運指情報の生成を行うための運指生成処理を実行した後、ステップSA7に移行する。そうでない場合には、次にそのステップSA7に移行する。
ステップSA7では、入力部4に設けられたその他のスイッチへの操作に対応するためのその他スイッチ処理を実行する。続くステップSA8では、鍵盤7へのユーザの操作に応じて楽音を発音させるための鍵盤処理を実行する。その次のステップSA9では、ユーザに曲を指定させ、指定された曲の自動演奏を実現させるための自動演奏処理を実行する。それ以降は、ステップSA10で表示部5に表示させるべき情報を表示させる表示処理、ステップSA11でその他処理を実行してから、上記ステップSA2に戻る。
図4以降に示すフローチャートは、上記全体処理内で直接的、或いは間接的に呼び出されるサブルーチン処理を示すものである。このことから以降、そのサブルーチン処理について詳細に説明する。
図4は、上記ステップSA4として実行される範囲設定処理のフローチャートである。次に図4を参照して、その設定処理について詳細に説明する。
先ず、ステップSC1では、モード設定スイッチがオンしたか否か判定する。そのスイッチをユーザが操作した場合、判定はYESとなり、次のステップSC2で変数modeに値の代入を行ってからステップSC7に移行する。そうでない場合には、判定はNOとなってステップSC3に移行する。
上記指定区間モード、全体モードの間の切り替えは、例えばモード設定スイッチが操作される度に行うようになっている。そのようにモード間の切り替えが行われる場合、ステップSC2で変数modeに代入される値は、それまでの値が0であれば1、それまでの値が1であれば0、である。
ステップSC3では、範囲設定スイッチがオンしたか否か判定する。そのスイッチをユーザが操作した場合、判定はYESとなり、ステップSC4で変数ev_s、或いはev_eへの値の代入をユーザの入力部4への操作に応じて行ってからステップSC7に移行する。そうでない場合には、判定はNOとなってステップSC5に移行する。
運指情報の生成対象とする区間(範囲)は、特には図示していないが、例えば先頭からの音符数で指定するようになっている。その指定は、数値を直接、入力させることで行わせても良いが、演奏データから楽譜を生成して表示部5に表示させることにより、表示部5上で指定できるようにさせても良い。当然のことながら、それら以外の方法を採用しても良い。
ステップSC5では、オプション設定スイッチがオンしたか否か判定する。そのスイッチをユーザが操作した場合、判定はYESとなり、ステップSC6で変数lookupb、及びlookupfのうちの少なくとも一方の値を変更させてから、ステップSC7に移行する。そうでない場合には、判定はNOとなってステップSC11に移行する。
ステップSC6では、変数lookupb、及びlookupfの値は、例えばオプション設定スイッチが操作される度に、(0,0)(前者は変数lookupbに代入される値、後者は変数lookupfに代入される値。以下、同様)→(0,1)→(1,0)→(1,1)→(0,0)の順序でサイクリックに変化させるようになっている。それにより、オプション設定スイッチを操作することで所望のオプションを設定できるようにさせている。
ステップSC7では、変数modeの値が0か否か判定する。その値が0、つまり全体モードが設定されている場合、判定はYESとなり、ステップSC8で変数me_sに0、変数me_eに変数ev_maxの値を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなってステップSC9に移行する。
ステップSC9では、変数me_sに、変数lookupbの値が0ならば変数ev_sの値、その変数lookupbの値が1ならば変数ev_sの値から定数COSTSEEKCNTを引いた値(その値が0より小さければ0)を代入する。次のステップSC10では、変数me_eに、変数lookupfの値が0ならば変数ev_eの値、その変数lookupfの値が1ならば変数ev_eの値に定数COSTSEEKCNTを加算した値(その値が変数ev_maxの値より大きければ変数ev_maxの値)を代入する。一連の処理はその後に終了する。
このようにして結果的に、運指情報の生成の対象となる区間範囲を示す値は変数me_s、me_eに代入される。それにより、それらの変数により指定される範囲(区間)を対象にして運指情報の生成を行うようにしている。上記定数COSTSEEKCNTはCPU1が実行するプログラム内で定義された変数か、或いは制御用データとしてROM2に格納されたデータである。これは他の定数も同様である。
一方、上記ステップSC5の判定がNOとなって移行するステップSC11では、同一フレーズ補正スイッチがオンしたか否か判定する。そのスイッチをユーザが操作した場合、判定はYESとなり、ステップSC12で変数phrcorに値の代入を行った後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
上記ステップSC12での変数phrcorへの値の代入は、例えばそれまでの値が0であれば1、それまでの値が1であれば0、を代入することで行うようになっている。それにより、内容が同一のフレーズを考慮した運指情報の補正を行うか否かを同一フレーズ補正スイッチへの操作により選択できるようにさせている。
図5は、図3に示す全体処理内でステップSA6として実行される運指生成処理のフローチャートである。次に図5を参照して、その生成処理について詳細に説明する。
先ず、ステップSB1では、変数loopcntへの0の代入を含め、各種変数の初期化を行う。次に移行するステップSB2では、変数me_s、me_eにそれぞれ代入された値で指定された範囲を対象にして運指情報を生成する指定区間運指生成処理を実行する。その実行後はステップSB3に移行する。
ステップSB3では、ステップSB2で生成される運指情報に従った演奏の難易度を評価するための評価処理を実行する。次のステップSB4では、変数loopcntの値が0でないか否か判定する。評価処理では、後述するように、難易度として、1音符平均の難易度(コスト)を算出し、算出した難易度が判定用の定数THRCOST2より小さければ、つまり生成された運指情報に従った演奏の難易度が許容範囲内と云えるのであれば、その運指情報は適切なものであるとして変数loopcntに0を代入するようにしている。このことから、直前のステップSB2の実行により生成された運指情報が適切なものであった場合、判定はNOとなり、ここで一連の処理は終了する。そうでない場合には、判定はYESとなって上記ステップSB2に戻る。
上記指定区間運指生成処理では、変数loopcntの値が0であれば運指情報の生成を行い、0以外の値であれば、その値に応じた運指情報に対する修正を行うようになっている。それにより、ステップSB4の判定がYESとなってステップSB2に戻った場合には、運指情報をより適切なものとするための修正を行うようにさせている。
図6、及び図7は、そのステップSB2として実行される指定区間運指生成処理のフローチャートである。次に図6、及び図7を参照して、その生成処理について詳細に説明する。
先ず、ステップSJ1では、変数loopcntの値が0か否か判定する。その値が0であった場合、判定はYESとなり、次にステップSJ2で1音符毎に運指情報を生成する逐次生成処理を実行し、その次のステップSJ3で変数me_tailに変数me_eの値、変数loopcntに1をそれぞれ代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなってステップSJ4に移行する。
ステップSJ4では、変数loopcntの値が1か否か判定する。その値が1でなかった場合、判定はNOとなってステップSJ9に移行する。そうでない場合には、判定はYESとなってステップSJ5に移行する。
ステップSJ5では、区間内の演奏データが示す演奏をフレーズで仮想的に分割するためのフレーズ分割処理を実行する。続くステップSJ6では、ステップSJ5でのフレーズ分割処理の実行で抽出される1フレーズ分の演奏データを対象に運指のパターンを適用するためのパターン適用処理を実行する。ステップSJ7にはその後に移行する。
上記フレーズ分割処理の実行により、詳細は後述するように、分割・抽出したフレーズの最後に位置する音符(データ)のインデックス値が変数me_tailに代入される。ステップSJ7では、その変数me_tailの値が変数me_eの値と等しいか否か判定する。区間内に存在する最後のフレーズの分割・抽出が終了した場合、変数me_tailには変数me_eの値が代入されることから、判定はYESとなり、ステップSJ8で変数loopcntに2を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
上記ステップSJ4の判定がNOとなって移行するステップSJ9では、変数loopcntの値が2か否か判定する。その値が2であった場合、判定はYESとなってステップSJ10に移行し、そうでない場合には、判定はNOとなって図7のステップSJ14に移行する。
ステップSJ10では、区間内の演奏データが示す演奏で発音される和音を判定する和音判定処理を実行する。続くステップSJ11では、その区間内における全ての運指の組み合わせを調査するための和音全数検査処理を実行する。ステップSJ12にはその後に移行する。
上記和音全数検査処理の実行により、詳細は後述するように、変数me_tailには変数me_eの値、または判定された和音の最後に位置する音符(データ)のインデックス値が代入される。ステップSJ12では、その変数me_tailの値が変数me_eの値と等しいか否か判定する。それらが一致する場合、判定はYESとなり、ステップSJ13で変数loopcntに3を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
上記ステップSJ9の判定がNOとなって移行する図7のステップSJ14では、変数loopcntの値が3か否か判定する。その値が3であった場合、判定はYESとなってステップSJ15に移行し、そうでない場合には、判定はNOとなってステップSJ19に移行する。
ステップSJ15では、区間内の演奏データが示す演奏で発音される分散和音を判定する分散和音判定処理を実行する。続くステップSJ16では、その区間内における全ての運指の組み合わせを調査するための分散和音全数検査処理を実行する。ステップSJ17にはその後に移行する。
上記分散和音全数検査処理の実行により、上記和音全数検査処理の実行時と同様に、変数me_tailには変数me_eの値、または判定された分散和音の最後に位置する音符(データ)のインデックス値が代入される。ステップSJ17では、その変数me_tailの値が変数me_eの値と等しいか否か判定する。それらが一致する場合、判定はYESとなり、ステップSJ18で変数loopcntに4を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
ステップSJ19では、変数loopcntの値が4か否か判定する。その値が4であった場合、判定はYESとなってステップSJ20に移行し、そうでない場合には、判定はNOとなってステップSJ24に移行する。
ステップSJ20では、運指コストが閾値として定めた定数THRCOST1よりも大きな音符を抽出する検索を行う修正個所検索処理を実行する。次のステップSJ21では、その処理の実行により抽出される修正対象範囲内における全ての運指の組み合わせを調査するための全数検査処理を実行する。ステップSJ22にはその後に移行する。
上記全数検査処理の実行により、他の全数検査処理の実行時と同様に、変数me_tailには変数me_eの値、または抽出された修正対象範囲の最後に位置する音符(データ)のインデックス値が代入される。ステップSJ22では、その変数me_tailの値が変数me_eの値と等しいか否か判定する。それらが一致する場合、判定はYESとなり、ステップSJ23で変数loopcntに5を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
ステップSJ24では、変数loopcntの値が5、且つ変数phrcorの値が1か否か判定する。変数loopcntの値が5,且つ変数phrcorの値が1であった場合、判定はYESとなり、ステップSJ25で同一フレーズ補正処理を実行し、更にステップSJ26で変数loopcntに0を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、次にステップSJ26の処理を実行する。
図5に示す運指生成処理内でステップSB2として実行される指定区間運指生成処理では、上述したように、実行する度に変数loopcntの値がインクリメントされる。それにより、最初に生成した運指情報に対し、変数loopcntの値に対応する内容に着目した補正を適切な運指情報が生成されるか、或いは着目する内容が無くなるまで順次、行うようにしている。そのようにして、適切(最適)な運指情報を生成するうえで必要な補正を必要に応じて行うようにすることにより、適切(最適)な運指情報を演奏データが示す演奏内容に応じて確実、且つより迅速に生成できるようになる。
次に、上記指定区間運指生成処理内で実行されるサブルーチン処理について詳細に説明する。
図8は、上記ステップSJ2として実行される逐次生成処理のフローチャートである。そのサブルーチン処理としては、始めに図8を参照して、逐次生成処理について詳細に説明する。その逐次生成処理は、区間内に発音される音符別に運指情報を生成していく処理である。
新たな押鍵に使うべき指として、その押鍵時に別の鍵の押鍵に使用中の指を割り当てることはできない。新たな押鍵に使うべき指はそのときの状況によって制限される。このことから、本実施の形態では、図9に示すように、手の状態管理用変数を指別に用意している。
その図9において、括弧を付して表記の「hfig」が指別にその状態を管理するためのデータ(以降「指状態データ」と呼ぶ)を示している。括弧内の数字は対応する指の番号(図2(a)に示すfigと同様)を示している。その指状態データは、「status」と表記の押鍵状態フラグ、「event」と表記の押鍵イベントのインデックス(値)(そのイベントを表す音符データMEのインデックス)、「posx」と表記の指の位置座標、から構成されている。
上記押鍵状態フラグとしては、押鍵中でない指では0、押鍵中の指では1を割り当てるようにしている。上記位置座標は、図2(a)に示すデータposxと同じく鍵盤座標で表している。逐次生成処理では、指状態データ(手の状態管理用変数の代入値)を更新しつつ、運指情報を生成する。指状態データを構成するデータが代入される変数は、これまでと同様に、「変数status」といったように図中に表記のシンボルを付して表記する。
先ず、ステップSK1では、変数meに変数me_sの値、変数pに、変数meの値で指定される音符データMEのデータposx(図中「ME[me].posx」と表記。以降、その表記法も併せて用いることとする)をそれぞれ代入し、各指の指状態データの更新を行う。その更新は、具体的には各変数status(図中「hfig[n].status」(n=0〜4)と表記)に0をそれぞれ代入し、各変数posxに親指から、変数pの値から4を減算した値、変数pの値から2を減算した値、変数pの値、変数pの値に2を加算した値、変数pの値に4を加算した値、をそれぞれ代入する。
ステップSK1に続くステップSK2では、変数meの値で指定される音符データMEを処理する時点での各指の状態を確認するための指状態確認処理を実行する。その次に移行するステップSK3では、その音符データMEのデータpitchで指定される鍵の押鍵に使うべき指を割り当てる指割り当て処理を実行する。その後はステップSK4に移行して、変数meの値が変数me_eの値と等しいか否か判定する。それらの値が等しい場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなり、ステップSK5で変数meの値をインクリメントしてから上記ステップSK2に戻る。それにより、変数meの値を順次、インクリメントしながら、変数meの値で指定される音符データMEに従った押鍵に使うべき指の割り当てを行う。
次に、上記ステップSK2として実行される指状態確認処理について、図10に示すそのフローチャートを参照して詳細に説明する。
先ず、ステップSL1では、着目する指を管理するための変数nに0、指の位置座標の最小値、最大値を管理するための変数posmin、及びposmaxにそれぞれ−1を代入する。続くステップSL2では、変数nの値が5より小さいか否か判定する。その値が5より小さい場合、判定はYESとなってステップSL3に移行する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
ステップSL3では、変数nの値で指定される指状態データを構成する変数status(図中「hfig[n].status」と表記)の値が1か否か判定する。変数nの値に対応する指が押鍵中である場合、その値は1であることから、判定はYESとなってステップSL4に移行し、そうでない場合には、判定はNOとなってステップSL7に移行する。
ステップSL4では、変数evに、変数nの値で指定される指状態データを構成する変数event(図中「hfig[n].event」と表記)の値を代入する。その代入後に移行するステップSL5では、変数evの値で指定される音符データMEを構成する、データtimeにデータgateを加算して得られる値が、変数meの値で指定される音符データMEを構成するデータtimeの値より小さいか否か判定する。変数meの値で指定される音符データMEに従った押鍵開始時に、変数evの値で指定される音符データMEに従った押鍵が終了している場合、前者は後者より小さくなる。このことから、そのような場合、判定はYESとなり、ステップSL6において変数nの値で指定される指状態データを構成する変数status(図中「hfig[n].status」と表記)の値として0を代入してからステップSL7に移行する。そうでない場合には、判定はNOとなり、次にそのステップSL7に移行する。
ステップSL7では、変数posminの値が−1、またはhfig[n].posxの値より大きいならば、その変数posminにhfig[n].posxの値を代入する。続くステップSL8では、変数posmaxの値が−1、またはhfig[n].posxの値より小さいならば、その変数posmaxにhfig[n].posxの値を代入する。その後は、ステップSL9で変数nの値をインクリメントしてから上記ステップSL2に戻る。
このようにして、指状態確認処理を実行することにより、変数meの値で指定される音符データMEに従った押鍵開始時に離鍵中とすべき指は離鍵中に設定され、その押鍵開始時に位置座標が最小値、及び最大値となる2つの指の座標値は変数posmin、posmaxにそれぞれ代入される。
図11は、図8に示す逐次生成処理内でステップSK3として実行される指割り当て処理のフローチャートである。次に図11を参照して、その割り当て処理について詳細に説明する。その割り当て処理では、押鍵に使われていない指を探しだし、着目する音符データMEに従って押鍵すべき鍵の座標値よりも小さい座標値に位置している指を優先的に押鍵に使うべき指として割り当てるようにしている。
先ず、ステップSM1では、変数nに0、変数ifigに−1をそれぞれ代入する。続くステップSM2では、変数nの値が5より小さいか否か判定する。その値が5より小さい場合、判定はYESとなってステップSM3に移行し、そうでない場合には、判定はNOとなってステップSM9に移行する。
ステップSM3では、hfig[n].statusの値が0か否か判定する。変数nの値で指定される指が押鍵に使われていない場合、その値は0であることから、判定はYESとなり、ステップSM5で変数ifigに変数nの値を代入してからステップSM6に移行する。そうでない場合には、判定はNOとなり、ステップSM4で変数nの値をインクリメントしてから上記ステップSM2に戻る。
ステップSM6では、hfig[n].posxの値がME[me].posxの値以下か否か判定する。変数nの値で指定される指の座標値が変数meの値で指定される音符データMEに従って押鍵すべき鍵の座標値以下であった場合、判定はYESとなってステップSM7に移行する。そうでない場合には、判定はNOとなり、ステップSM4で変数nの値のインクリメントを行う。そしてステップSM2の判定がNOになった場合は、ステップSM9に移行する。ステップSM9では、変数ifigが−1か否か判定する。変数ifigが−1の場合は、判定がYESとなり、ステップSM10で変数ifigに0を代入してからステップSM7に移行する。そうでない場合には、判定はNOとなってステップSM7に移行する。
ステップSM7では、hfig[ifig].statusに1、hfig[ifig].eventに変数meの値、hfig[ifig].posxにME[me].posxの値、ME[me].figに変数ifigの値、をそれぞれ代入する。次のステップSM8では、押鍵に割り当てた指以外の指の座標値を指定する指位置指定処理を実行する。その実行後、一連の処理を終了する。
図12は、その指位置指定処理のフローチャートである。次にその指定処理について、図12を参照して詳細に説明する。その指定処理では、全ての指を対象に位置させるべき座標値の基準からの変位量を算出して配列変数figtmpの対応する要素に代入し、押鍵を割り当てた指以外の指を位置させるべき座標値として、対応する要素に代入した座標値から算出される値を設定するようにしている。
先ず、ステップSN1では、変数nに0、変数rangeに、変数posmaxの値から変数posminの値を減算した値を代入する。次のステップSN2では、変数nの値が5より小さいか否か判定する。その値が5より小さい場合、判定はYESとなってステップSN3に移行し、そうでない場合には、判定はNOとなってステップSN5に移行する。
ステップSN3では、hfig[n].posxの値からhfig[0].posxの値を減算した値を、hfig[4].posxの値からhfig[0].posxの値を減算した値で除算し、その除算値を変数rangeの値に乗算して得られる変位量を、配列変数figtmpの変数nの値で指定される要素figtmp[n]に代入する。その代入後は、ステップSN4で変数nの値をインクリメントしてから上記ステップSN2に戻る。
一方、ステップSN5では、変数nに0を代入する。次のステップSN6では、変数nの値が5より小さいか否か判定する。その値が5より小さい場合、判定はYESとなってステップSN7に移行する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
ステップSN7では、変数nの値が変数ifigの値と等しくないか否か判定する。それらの値が一致していた場合、判定はNOとなり、ステップSN9で変数nの値をインクリメントしてからステップSN6に戻る。そうでない場合には、判定はYESとなってステップSN8に移行し、hfig[n].posxの値として、hfig[ifig].posxの値に、要素figtmp[n]の値から要素figtmp[ifig]の値を減算した値を代入する。その代入後は、ステップSN9に移行して変数nの値をインクリメントする。
図6、及び図7に示す指定区間運指生成処理内で実行されるサブルーチン処理の説明に戻る。
図13は、その生成処理内でステップSJ5として実行されるフレーズ分割処理のフローチャートである。次にその分割処理について、図13を参照して詳細に説明する。その分割処理は、区間内の演奏をフレーズで仮想的に分割して1フレーズ分の演奏を抽出するための処理である。
先ず、ステップSF1では、フレーズ分割の開始位置を管理するための変数mefに、変数me_tailの値に1を加算した値(その加算値が変数me_eの値より大きければ変数me_sの値)を代入する。次のステップSF2では、その終了位置として考えられる最大位置を管理するための変数medに、変数mefの値に定数DIVNOTECNTを加算した値(その加算値が変数me_eの値より大きければ変数me_eの値)を代入する。その後は、ステップSF3で変数meに変数mefの値、変数metに変数medの値、変数noteonintvに定数THRINTVをそれぞれ代入してからステップSF4に移行する。
本実施の形態では、フレーズ分割は隣接する2音間の発音開始時刻の時間差に着目して行っている。上記定数THRINTVはその時間差として考えられる最小の閾値として定めたものである。そのような定数THRINTVを用意したことにより、変数medの値で指定される音符までの演奏区間の間で、その定数THRINTVより長い時間差のなかで最大のものをフレーズの境界としてフレーズ分割を行うようにしている。そのフレーズ分割は、ステップSF4以降の処理を実行することで実現される。
先ず、ステップSF4では、変数meの値が変数medの値と等しいか否か判定する。それらの値が等しい場合、判定はYESとなってステップSF8に移行し、そうでない場合には、判定はNOとなってステップSF5に移行する。
ステップSF5では、変数noteonintvの値が、ME[me+1].timeの値からME[me].timeの値を減算した値より小さいか否か判定する。変数meの値で指定される音符とその次に発音される音符との間の発音開始時刻の時間差が変数noteonintvの値で表される時間差より大きい場合、判定はYESとなり、ステップSF6において、変数metに変数meの値、変数noteonintvにME[me+1].timeの値からME[me].timeの値を減算した値をそれぞれ代入し、更にステップSF7で変数meの値をインクリメントしてから上記ステップSF4に戻る。そうでない場合には、判定はNOとなって次にステップSF7の処理を実行する。
そのステップSF4の判定がYESとなって移行するステップSF8では、変数me_topに変数mefの値、変数me_tailに変数metの値をそれぞれ代入する。続くステップSF9では、変数mefの値と変数metの値で指定される区間内に存在する音符データME中のデータpid、pstatの更新を行う。その更新は、各データpidとして0をそれぞれ設定し、データpstatとしては、変数mefの値で指定される音符データMEのものには0、変数metの値で指定される音符データMEのものには2、それ以外の音符データMEのものには1をそれぞれ設定することで行う。一連の処理はその更新後に終了する。
上記ステップSF8で値が代入される変数me_top、me_tailは、分割により抽出されたフレーズの先頭位置、終了位置を音符データMEのインデックス値で表すものとして扱われる。フレーズ分割処理に続けて実行されるパターン適用処理では、それらのインデックス値で指定される区間として抽出された1フレーズに運指のパターンを適用させる。
図14は、そのパターン適用処理のフローチャートである。次にその適用処理について、図14を参照して詳細に説明する。
1フレーズ分の演奏に適用可能な運指のパターンを示すパターンデータは、ROM2に制御用データとして格納されている。そのパターンデータは、例えば図15に示すような構成でROM2に格納されている。それにより、適用処理は、ROM2に格納されたパターンデータを参照して行うようになっている。
図15中に括弧を付して表記の「FP」はパターンデータを示している。それにより、ROM2には、計FP_N個のパターンデータが格納されている。括弧内の数値は、パターンデータFPの特定用に割り当てられた番号(パターン番号)を表している。
各パターンデータFPは、音符単位のデータ(以下「音符データ」と呼ぶ)が複数、まとめられて構成されている。図15中に括弧を付して表記の「note」はその音符データを表している。括弧内の数値は、パターンデータFPの先頭を基準にした音符データnoteの位置を表している。音符データnoteの指定はその数値により行われる。「FPN_N」は各パターンデータFPを構成する音符データ数に1を加算した値である。
音符データnoteは、「bw」と表記の鍵盤種類、「pint」と表記の前音符との発音開始時刻の時間間隔、「nint」と表記の次音符との発音開始時刻の時間間隔、及び「fig」と表記の運指番号(押鍵に用いる指の番号)、を備えた構成となっている。鍵盤種類は、白健では0、黒鍵では1、最後の音符データでは−1で表している。
図14に示す適用処理では先ず、ステップSQ1で変数patに0を代入する。その変数patは、注目するパターンデータFPを管理するためのものである。その変数patに0を代入した後はステップSQ2に移行して、変数patの値がパターンデータFPの総数FP_Nより小さいか否か判定する。パターンの適用のために全てのパターンデータFPに注目した場合、変数patの値は総数FP_N以上となる。このことから、その場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSQ3に移行する。
ステップSQ3では、変数matchに1を代入する。続くステップSQ4では、変数patの値で指定されるパターンデータFPに着目したパターンマッチング処理を実行する。その後に移行するステップSQ5では、変数matchの値が0か否か判定する。その値が0であった場合、判定はYESとなり、ステップSQ6で変数patの値をインクリメントしてから上記ステップSQ2に戻る。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
図16は、上記ステップSQ4として実行されるパターンマッチング処理のフローチャートである。ここで図16を参照して、そのマッチング処理について詳細に説明する。そのマッチング処理は、変数patの値で指定されるパターンデータFP[pat]と抽出フレーズの間のマッチングを行い、それらの間の一致している部分を確認するための処理である。
パターンデータFPを構成する音符データnoteは、鍵盤種類(押鍵すべき鍵の種類:データbw)、前音符との発音開始時刻の時間間隔(データpint)、次音符との発音開始時刻の時間間隔(データnint)、及び運指番号(データfig)、を備えた構成である。それにより、パターンマッチングは、パターンデータFP[pat]と抽出フレーズのそれぞれ先頭に位置している音符データ(noteおよびME)から、押鍵していくべき鍵の種類の流れ、及びその押鍵間隔の許容範囲内での一致を確認していく形で行うようにしている。許容範囲内で一致するか否か判定するために、定数THRINTV2を用意している。
先ず、ステップSR1では、変数ppに変数me_topの値、変数pcntに0をそれぞれ代入する。変数ppは演奏データのなかで注目する音符データMEを管理するために用いられ、変数pcntはパターンデータFP[pat]のなかで注目する音符データnoteの管理(及び一致している音符データの個数のカウント)に用いられる。それらの代入後に移行するステップSR2では、変数ppの値が変数me_tailの値より大きいか否か判定する。変数ppの値が変数me_tailの値より大きい場合、判定はYESとなってステップSR10に移行し、そうでない場合には、判定はNOとなってステップSR3に移行する。
ステップSR3では、各種変数への値の代入を行う。具体的には、変数fpに、パターンデータFP[pat]のなかで変数pcntの値で指定される音符データ(図中「FP[pat].note[pcnt]」と表記。以降、その表記法も用いる)を代入し、変数ppの値が0であれば0、そうでなければ変数ppで指定される音符とその前音符間の発音開始時刻の時間間隔(=ME[pp].time−ME[pp−1].time)を変数pintに代入し、変数ppの値が変数ev_maxの値と等しければ0、そうでなければ変数ppで指定される音符とその次音符間の発音開始時刻の時間間隔(=ME[pp+1].time−ME[pp].time)を変数nintに代入する。そのような代入を行った後、ステップSR4に移行する。
ステップSR4では、変数fpに代入されたFP[pat].note[pcnt]のなかのデータbw(図中「fp.bw」と表記)の値が−1か否か判定する。そのデータbwの値が−1であった場合、判定はYESとなってステップSR10に移行し、そうでない場合には、判定はNOとなってステップSR5に移行する。ここでのYESの判定は、着目するパターンデータFP[pat]を構成する音符データnoteが全て抽出フレーム中の対応する音符データMEと一致判定条件(鍵盤種類が一致し、且つ前音符、及び次音符との発音開始時刻の時間間隔が許容範囲内でそれぞれ一致するという条件)を満たしていることを意味する。
ステップSR5では、fp.bwの値がME[pp].posxを2で割った余り(図中「ME[pp].posx %2」と表記。以降、その表記法も用いる)と等しくないか否か判定する。音符データnote[pcnt]中のデータbwが表す鍵の種類が音符データME[pp]中のデータposxで指定される鍵の種類と同じであった場合、それらは一致することから、判定はNOとなってステップSR6に移行する。そうでない場合には、判定はYESとなり、ステップSR9で変数matchに0を代入した後、一連の処理を終了する。
ステップSR6では、変数pintの値からfp.pintの値を引いた値の絶対値が上記定数THRINTV2より大きいか否か判定する。パターンデータFPと抽出フレーズ間で前音符との時間間隔が許容範囲内で一致しなかった場合、その関係が満たされることから、判定はYESとなってステップSR9に移行し、そうでない場合には、判定はNOとなってステップSR7に移行する。
ステップSR7では、変数nintの値からfp.nintの値を引いた値の絶対値が上記定数THRINTV2より大きいか否か判定する。パターンデータFPと抽出フレーズ間で次音符との時間間隔が許容範囲内で一致しなかった場合、その関係が満たされることから、判定はYESとなってステップSR9に移行する。そうでない場合には、つまり一致判定条件が全て満たされている場合には、判定はNOとなり、ステップSR8で変数pp、及びpcntの値をそれぞれインクリメントしてから上記ステップSR2に戻る。それにより、ステップSR2でのYESの判定は、抽出フレーズを構成する音符データMEは全て、パターンデータFP[pat]を構成する音符データnoteのなかで対応する音符データnoteと一致判定条件を満たしていることを意味している。
ステップSR2、或いはSR4の判定がYESとなって移行するステップSR10では、変数pcntの値が0か否か判定する。その値が0であった場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなってステップSR11に移行する。
ステップSR11以降では、パターンデータFP[pat]で定義された運指番号を抽出フレーズを構成する各音符データME中のデータfigとして設定するための処理が行われる。
先ず、ステップSR11では、変数ppに変数me_topの値、変数nに0をそれぞれ代入する。続くステップSR12では、ME[pp].figとして、パターンデータFP[pat]の変数nの値で指定される音符データnote[n]中のデータfig(図中「FP[pat].note[n].fig」と表記)を設定し、変数nの値をインクリメントする。
ステップSR12に続くステップSR13では、変数nの値が変数pcntの値より小さいか否か判定する。パターンデータFP[pat]で定義された運指番号の抽出フレーズを構成する各音符データME中のデータfigとしての設定が完了した場合、その関係は満たされなくなることから、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなり、ステップSR14で変数ppの値をインクリメントしてから上記ステップSR12に戻る。それにより、データfigの設定を継続させる。
図17は、図6、及び図7に示す指定区間運指生成処理内でステップSJ10として実行される和音判定処理のフローチャートである。次にその判定処理について、図17を参照して詳細に説明する。本実施の形態では、発音開始時刻が同じ(許容範囲内で一致する)3音以上の音符群を和音の構成音として検出するようにしている。
先ず、ステップSE1では、変数me_tailの値に1を加算した値が変数me_eを越えなければその加算値、それを越えれば変数me_sの値を変数meに代入する。次のステップSE2では、変数meの値が、変数me_eの値から1を引いた値以上か否か判定する。変数meの値がその減算値以上であった場合、判定はYESとなり、ステップSE3で変数me_top、及びme_tailに変数me_eの値を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなってステップSE4に移行する。ここでのYESの判定は、和音の検出が全て終了したことを意味している。
ステップSE4では、ME[me].timeの値がME[me+1].timeの値と一致するか否か判定する。変数meの値で指定される音符とその次音符の発音開始時刻が一致している場合、判定はYESとなり、ステップSE6で変数cntに2、変数neに変数meの値に2を加算した値をそれぞれ代入してからステップSE7に移行する。そうでない場合には、判定はNOとなり、ステップSE5で変数meの値をインクリメントしてから上記ステップSE2に戻る。
ステップSE7では、ME[ne].timeの値がME[me].timeの値と一致するか否か判定する。変数meの値で指定される音符と変数neの値で指定される音符の発音開始時刻が一致している場合、判定はYESとなり、ステップSE8で変数cnt、及びneの各値のインクリメントを行った後、ステップSE9に移行する。そうでない場合には、判定はNOとなり、ステップSE10に移行する。
ステップSE9では、変数neの値が変数me_eの値より大きいか否か判定する。その大小関係が成立している場合、判定はYESとなってステップSE10に移行する。そうでない場合には、判定はNOとなり、上記ステップSE7に戻る。それにより、変数meの値で指定される音符の発音開始時刻と発音開始時刻が一致しない音符が見つかるか(ステップSE7のNOの判定)、或いは発音開始時刻を比較する対象となる音符が無くなるまで(ステップSE9のYESの判定)、ステップSE7〜SE9で形成される処理ループを繰り返し実行する。
ステップSE10では、変数cntの値が3以上か否か判定する。その値が3、つまり発音開始時刻が一致すると見なす音符が3つ以上、見つかった場合、判定はYESとなり、ステップSE11で変数meの値を変数me_top、変数cntの値から1を引いた値に対し、変数meの値を加算した値を変数me_tailにそれぞれ代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ステップSE12で変数meにそれまでの値に変数cntの値を加算した値を新たに代入してから上記ステップSE2に戻る。それにより、和音の構成音の検出を継続させる。
図6、及び図7に示す指定区間運指生成処理では、上記和音検出処理の実行後に移行するステップSJ11で和音全数検索処理を実行する。次にその検索処理について、図18に示すそのフローチャートを参照して詳細に説明する。
先ず、ステップSP1では、変数me_topの値が変数me_tailの値と等しいか否か判定する。上述したように、それらの変数には、ステップSE2の判定がYES、つまり和音の検出が全て終了した場合に同じ値が代入される。このことから、そのような場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなってステップSP2に移行し、全数検査処理を実行する。その後、一連の処理を終了する。
次に上記全数検査処理について、図19に示すそのフローチャートを参照して詳細に説明する。その全数検査処理は、図6、及び図7に示す指定区間運指生成処理内ではステップSJ21として実行される。
先ず、ステップST1では、指定の区間内の運指上のコストを算出する区間コスト算出処理を実行する。次のステップST2では、その算出処理の実行により変数costtmpに代入されたコストを変数costbest、変数me_topの値を変数me、1を変数loopmax、0を変数loopにそれぞれ代入する。そして、変数me_topと変数me_tailで指定される区間の運指を、配列変数figtmpにコピーする。そのコピーは、変数meに変数me_topの値から変数me_tailの値まで順次、代入しながら、その変数meの値で指定される音符データME[me]のデータfigを、初期値が0でその値から変数meの値と同じタイミングで順次インクリメントする変数cntの値で指定される配列変数figtmp[cnt]に設定(つまりfigtmp[cnt]←ME[me].fig)することで行われる。そして全ての運指のコピーが終了した後で、変数me_topの値を改めて変数meに代入する。ステップST3にはその後に移行する。
ステップST3〜ST5では、変数loopmaxに、区間内における運指の組み合わせ総数、つまりその区間内における全ての運指の組み合わせの数を求めて代入するための処理が行われる。
先ず、ステップST3では、変数loopmaxに、それまでの値に5を掛けた値を新たに代入する。続くステップST4では、変数meの値が変数me_tailの値と等しいか否か判定する。それらの値が一致した場合、判定はYESとなってステップST6に移行する。そうでない場合には、判定はNOとなり、ステップST5で変数meの値をインクリメントしてから上記ステップST3に戻る。それにより、ステップST4の判定がYESとなった場合、変数loopmaxには組み合わせ総数が代入されていることになる。
ステップST6では、変数loopの値が変数loopmaxの値より小さいか否か判定する。その大小関係が成立している場合、判定はYESとなり、ステップST7に移行する。そうでない場合には、判定はNOとなり、ステップST18に移行する。ステップST18では、変数me_topと変数me_tailで指定される区間の運指に、配列変数figtmpの運指をコピーする。そのコピーは、変数meに変数me_topの値から変数me_tailの値まで順次、代入しながら、その変数meの値で指定される音符データME[me]のデータfigに、初期値が0でその値から変数meの値と同じタイミングで順次インクリメントする変数cntの値で指定される配列変数figtmp[cnt]の運指を設定(つまりME[me].fig←figtmp[cnt])することで行われる。その後、一連の処理を終了する。
ステップST7では、変数meに変数me_topの値、変数digitに1、変数cntに0をそれぞれ代入する。次のステップST8では、音符データMEの変数meの値で指定される要素ME[me]のデータfigに、変数loopの値を変数digitの値で割った除算値を5で割って得られる余り(図中「(loop/digit)%5」と表記)を代入し、その代入後には変数digitにそれまでの値に5を掛けた値を代入し、変数cntの値をインクリメントする。その後に移行するステップST9では、変数meの値が変数me_tailの値と等しいか否か判定する。それらの値が等しい場合、判定はYESとなってステップST11に移行する。そうでない場合には、判定はNOとなり、ステップST10で変数meの値をインクリメントしてから上記ステップST8に戻る。
上記ステップST8〜ST10で形成される処理ループをステップST9の判定がYESとなるまで繰り返し実行することにより、要素ME[me].figには順次、運指番号が代入される。その運指番号は、変数loopの値を固定にして変数digitの値のみを随時それまでの5倍とすることにより、変数loopの値に応じて固有に変化していく数値となる。
ステップST11では、音符データMEに代入した運指番号に従った運指上のコストを算出するために、区間コスト算出処理を実行する。その実行後はステップST12に移行する。
ステップST12では、変数costbestの値が変数costtmpの値より大きいか否か判定する。変数costtmpに代入されるコストは、その値が大きくなるほど難易度が高いことを示している。それにより、今回、音符データMEの各要素に代入していった運指番号の組み合わせから求めたコストがそれまでのものより小さい場合、判定はYESとなってステップST13に移行し、そうでない場合には、判定はNOとなってステップST17に移行する。
ステップST13では、変数costbestに変数costtmpの値、変数meに変数me_topの値、変数cntに0をそれぞれ代入する。次のステップST14では、ME[me].figの値を要素figtmp[cnt]のデータとして設定し、その設定後に変数cntの値をインクリメントする。その後に移行するステップST15では、変数meの値が変数me_tailの値と等しいか否か判定する。それらの値が一致する場合、判定はYESとなり、ステップST17で変数loopの値をインクリメントしてから上記ステップST6に戻る。そうでない場合には、判定はNOとなり、ステップST16で変数meの値をインクリメントしてから上記ステップST14に戻る。それにより、ステップST6の判定がNOとなった時点では、コストが最も低い運指(指の割り当て)の組み合わせが配列変数figtmpに設定されていることになる。
図20は、上記ステップST1、或いはST11で実行される区間コスト算出処理のフローチャートである。次にその算出処理について、図20に示すそのフローチャートを参照して詳細に説明する。
先ず、ステップSU1では、変数costtmpに0、変数meに変数me_topの値をそれぞれ代入する。続くステップSU2では、変数meの値が変数me_tailの値より大きいか否か判定する。前者が後者より大きい場合、判定はYESとなり、ステップSU6で変数costtmpに、それまでの値を音符の総数(=me_tail−me_top+1)で割った値、つまり1音符当たりの平均コストを代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなってステップSU3に移行する。
ステップSU3では、0から定数COSTSEEKCNT未満までの変数nの値で指定される配列変数costsの要素costs[n]に0をそれぞれ代入し、変数cntにも0を代入する。その次に移行するステップSU4では、変数meの値で指定される音符に着目してコストを算出する指定音コスト算出処理を実行する。その実行後は、ステップSU5に移行して、0から変数cntの値未満までの変数nの値で指定される要素costs[n]に代入されたコストの平均値を算出し、その算出結果をME[me].costとして設定し、変数costtmpに、それまでの値にME[me].costの値を加算した値を代入し、変数meの値をインクリメントする。その後は上記ステップSU2に戻る。
図21は、上記ステップSU4として実行される指定音コスト算出処理のフローチャートである。次に図21を参照して、そのコスト算出処理について詳細に説明する。
先ず、ステップSV1では、変数fにME[me].fig、変数pにME[me].posx、変数bwに変数pを2で割った余り、変数menに変数meの値に1を加算した値、をそれぞれ代入する。その次に移行するステップSV2では、変数meの値が変数me_tailの値以上か、または変数cntの値が定数COSTSEEKCNT以上か否か判定する。変数meの値が変数me_tailの値以上か、または変数cntの値が定数COSTSEEKCNT以上であった場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、つまり変数meの値が変数me_tailの値未満、且つ変数cntの値が定数COSTSEEKCNT未満であった場合には、判定はNOとなってステップSV3に移行する。
ステップSV3では、変数nfにME[men].fig、変数npにME[men].posxをそれぞれ代入する。続くステップSV4では、変数pの値が変数npの値より小さいか否か判定する。変数meの値で指定される音符が変数menの値で指定される音符より低音であった場合、変数pの値は変数npの値より小さくなることから、判定はYESとなり、ステップSV5で変数pmに0、変数intvに変数npの値から変数pの値を引いた値(音符間のピッチ差)をそれぞれ代入してからステップSV7に移行する。そうでない場合には、判定はNOとなり、ステップSV6で変数pmに1、変数intvに変数pの値から変数npの値を引いた値をそれぞれ代入してからそのステップSV7に移行する。変数pの値が変数npの値より小さいということは、発音させるべき音符のピッチ変化方向は増加の方向にあることを意味する。
ステップSV7では、変数intvの値が定数MAXINTV未満か否か判定する。その定数MAXINTVは、運指により押鍵を行う難易度が極めて高いと考えられる鍵間(ピッチ差)を判定するために用意したものである。このことから、着目する2つの音符の間にそのようなピッチ差が存在している場合、判定はNOとなり、ステップSV8で要素costs[cnt]にコストの最大値として設定の定数MAXCOSTを代入し、更にステップSV9で変数cnt、menの各値をインクリメントしてから上記ステップSV2に戻る。一方、そうでない場合には、判定はYESとなり、ステップSV10で要素costs[cnt]に、運指コストテーブルCTから抽出される値をコストとして代入してからステップSV11に移行する。
図22は、その運指コストテーブルCTのデータ構成を説明する図である。そのテーブルCTは、ROM2に制御用データとして格納されている。
図22中、「bw」は鍵盤種類(0は白鍵、1は黒鍵)、「pm」はピッチ変化方向(0は増加方向、1は減少方向)、「fig1」は変数meの値で指定される音符の指番号、「fig2」は変数menの値で指定される音符の指番号、「intv」はそれら2つの音符間のピッチ差、をそれぞれ表している。それにより、テーブルCTは、それらのデータ、つまり変数bw、pm、f、nf、及びintvの各値の組み合わせで示される状況別に、その状況下での運指のコストを格納したものとなっている。このことから、要素costs[cnt]には、変数bw、pm、f、nf、及びintvの各値で指定される欄に格納されたコストが抽出して代入される。図22では、5次元の配列変数CTの形でテーブルCTを表記している。
図21の説明に戻る。
ステップSV11では、変数fの値が変数nfの値と等しく、かつ変数pの値が変数npの値と等しくないか否か判定する。変数f、nfの値(指番号)が等しく、かつ変数pの値と変数npの値が等しくない(ピッチ(押鍵すべき鍵の音高)が等しくない)場合、判定はYESとなり、ステップSV12で変数sfに1を代入した後、ステップSV14に移行する。そうでない場合には、つまり変数fの値が変数nfの値と等しくないか、或いは変数pの値が変数npの値と等しいような場合には、判定はNOとなり、ステップSV13で変数sfに0を代入した後、そのステップSV14に移行する。
ステップSV14では、ME[me].timeがME[men].timeと等しいか否か判定する。変数me、menの各値で指定される音符の発音開始時刻が同じ場合、判定はYESとなってステップSV15に移行し、そうでない場合には、判定はNOとなってステップSV17に移行する。
ステップSV15では、変数sfの値が1か、または変数fの値が変数nfの値(指番号)より大きいか否か判定する。演奏データでは、発音開始時刻が同じ音符群はピッチの小さな順に配列されている。このことから、発音開始時刻が同じでピッチが異なる2つの音符を同じ指で押鍵するか、またはピッチが大きいほうの音符を親指、或いは親指に近いほうの指で押鍵しなければならない運指であった場合、判定はYESとなり、ステップSV16で要素costs[cnt]に定数MAXCOSTを代入してから上記ステップSV9に移行する。そうでない場合には、つまり発音開始時刻が同じでピッチが異なる2つの音符を同じ指で押鍵せず、かつピッチが大きいほうの音符を親指、或いは親指に近いほうの指で押鍵しない運指であった場合には、判定はNOとなってそのステップSV9に移行する。
ステップSV17では、変数cntの値が0、かつ変数sfの値が1か否か判定する。変数cntの値の0は、変数menの値で指定される音符は先頭の音符の次に位置していることを意味する。このことから、先頭、及びその次に位置する2つのピッチが異なる音符を同じ指で押鍵する運指であった場合、判定はYESとなって上記ステップSV16に移行し、そうでない場合には、判定はNOとなって上記ステップSV9に移行する。
このようにして、本実施の形態では、難易度の高い困難な運指の検出を行い、それによって検出された運指のコストとして定数MAXCOSTを設定するようにしている。それにより、設定された困難な運指はコストに大きく反映させている。
図6、及び図7に示す指定区間運指生成処理内で実行されるサブルーチン処理の説明に戻る。
図23、及び図24は、その生成処理内でステップSJ15として実行される分散和音判定処理のフローチャートである。次に図23、及び図24を参照して、その判定処理について詳細に説明する。
先ず、ステップSD1では、変数me_tailの値に1を加算した値が変数me_eの値を越えるならば変数me_sの値、そうでなければその加算値を変数meに代入する。次のステップSD2では、変数meの値が変数me_eの値と等しいか否か判定する。それらの値が一致している場合、判定はYESとなり、ステップSD3で変数me_top、及びme_tailにそれぞれ変数me_eの値を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ステップSD4に移行する。
ステップSD4では、変数tcに0、変数npに変数meの値、変数steptimeにME[np+1].timeからME[np].timeを減算した値(変数npの値で指定される音符とその次音符間の発音開始時刻の時間間隔)をそれぞれ代入する。その後に移行するステップSD5では、変数tcの値が定数MAXARPの2倍以上、または変数npの値が変数me_eの値以上か否か判定する。変数tcの値が定数MAXARPの2倍以上、または変数npの値が変数me_eの値以上であった場合、判定はYESとなってステップSD8に移行する。そうでない場合には、つまり変数tcの値が定数MAXARPの2倍未満、かつ変数npの値が変数me_eの値未満であった場合には、判定はNOとなってステップSD6に移行する。上記定数MAXARPは、分散和音の構成音数として考えられる最大値として設定したものである。その最小値は、定数MINARPとして設定している。
ステップSD6では、変数tcの値が0でなく、かつ変数steptimeの値がME[np+1].timeからME[np].timeを減算した値と等しくないか否か判定する。変数tcの値が0でないことは、減算値が示す発音開始時刻の時間間隔は、変数meの値で指定されない音符とその次音符間のものであることを意味する。このことから、その時間間隔が変数meの値で指定される音符とその次音符間のそれと一致しない場合、判定はYESとなってステップSD8に移行する。そうでない場合には、判定はNOとなり、ステップSD7において、配列変数pitvecの変数tcの値で指定される要素pitvec[tc]にME[np+1].pitchからME[np].pitchを減算した値(隣り合う音符のピッチ差)を代入し、その代入後に変数tc、及びnpの各値をインクリメントしてから上記ステップSD5に戻る。それにより、変数tc、及びnpの各値を順次インクリメントしながら、分散和音が存在する可能性のある区間の抽出を行う。
上記ステップSD5、或いはSD6の判定がYESとなって移行するステップSD8では、変数maxfrに、変数tcの値を2で割った値を代入する。その代入後はステップSD9に移行して、変数maxfrの値が定数MINARP未満か否か判定する。その値が定数MINARP未満であった場合、判定はYESとなり、ステップSD10で変数meにそれまでの値に変数tcの値を加算した値を代入してから上記ステップSD2に戻る。そうでない場合には、判定はNOとなり、図24のステップSD11に移行する。
ステップSD9でのNOの判定は、変数me、npの各値で指定される区間内に分散和音が存在する可能性があることを意味する。このことから、そのステップSD11以降では、その区間内に存在する分散和音を特定するための処理が行われる。
先ず、ステップSD11では、変数frに定数MINARPを代入する。続くステップSD12では、変数frの値が変数maxfrの値より大きいか否か判定する。変数frの値が変数maxfrの値より大きい場合、判定はYESとなって図23のステップSD10に移行し、そうでない場合には、判定はNOとなってステップSD13に移行する。
ステップSD13では、変数nに0を代入する。次のステップSD14では、変数nの値が変数frの値未満か否か判定する。変数nの値が変数frの値以上であった場合、判定はNOとなってステップSD18に移行する。そうでない場合には、判定はYESとなり、ステップSD15に移行して、要素pitvec[n]の値に要素pitvec[n+fr]の値を掛けた値が0未満か否か判定する。各要素pitvec[]には、隣り合う音符間のピッチ差が代入されている。このため、変数frの値分、離れた2つの音符でその次音符とのピッチ差の符号(ピッチ変化方向)が異なる場合、判定はYESとなり、ステップSD17で変数frの値をインクリメントしてから上記ステップSD12に戻る。そうでない場合には、判定はNOとなり、ステップSD16で変数nの値をインクリメントしてから上記ステップSD14に戻る。
ステップSD18では、要素pitvec[fr]の値に要素pitvec[fr−1]の値を掛けた値が0未満か否か判定する。変数frの値で指定される音符とその前後に位置する各音符との間のピッチ差の符号(ピッチ変化方向)が異なる場合、判定はYESとなり、ステップSD19に移行する。すなわち、一般的な分散和音はピッチの低い音から始まるため、ステップSD18の判定がYESとなる。そしてステップSD19では変数meの値を変数me_topに、変数meの値に変数frの値を加算し、その加算結果から1を引いて得られる値を変数me_tailにそれぞれ代入した後、一連の処理を終了する。つまり分散和音の構成音が存在していると見なす区間を、変数me_top、及びme_tailの各値で指定する。一方ステップSD18の判定がNOである場合は、次にステップSD17に移行する。
図6、及び図7に示す指定区間運指生成処理内では、上記分散和音判定処理に続いてステップSJ16で分散和音全数検査処理を実行する。次にその検査処理について、図25に示すそのフローチャートを参照して詳細に説明する。
先ず、ステップSG1では、変数me_topの値が変数me_tailの値と等しいか否か判定する。それらの値が等しい場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなり、次にステップSG2で図19に示す全数検査処理を実行してからステップSG3に移行する。
ステップSG3では、変数me_topの値を変数metmpに、変数me_tailの値から変数me_topの値を減算し、その減算結果に1を加算して得られる値(分散和音の構成音数)を変数dにそれぞれ代入する。続くステップSG4では、ME[metmp+d].figとしてME[metmp].figを設定し、その設定後に変数metmpの値をインクリメントする。その後に移行するステップSG5では、変数metmpの値が変数me_tailの値より大きいか否か判定する。変数metmpの値が変数me_tailの値より大きい場合、判定はYESとなり、ステップSG6において、変数me_topにそれまでの値に変数dの値を加算した値、変数me_tailにそれまでの値に変数dの値を加算した値をそれぞれ代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなって上記ステップSG4に戻る。
分散和音の構成音が存在していると見なす区間は変数me_top、及びme_tailの各値で指定される。上述の分散和音判定処理では、2つの分散和音が連続する区間を対象に抽出するようにしている。それにより、本実施の形態では、最初の分散和音の構成音を押鍵していく運指をその次の分散和音に対しても適用させるようにしている。
図26は、図6、及び図7に示す指定区間運指生成処理内でステップSJ20として実行される修正箇所検索処理のフローチャートである。次にその検索処理について、図26を参照して詳細に説明する。
先ず、ステップSH1では、変数me_tailの値に1を加算した値が変数me_eの値以下であればその加算値、そうでなければ変数me_sの値を変数mepに代入する。次のステップSH2では、変数meに変数mepの値に1を加算した値を代入する。その次に移行するステップSH3では、変数meの値が変数me_eの値より大きいか否か判定する。変数meの値が変数me_e以下であった場合、判定はNOとなってステップSH4に移行する。そうでない場合には、判定はYESとなり、ステップSH13で変数me_top、及びme_tailにそれぞれ変数me_eの値を代入した後、一連の処理を終了する。
ステップSH4では、ME[me].costが定数THRCOST1以上か否か判定する。その定数THRCOST1は、運指を修正すべき箇所のコストの閾値として設定したものである。このことから、変数meの値で指定される音符を発音させるための運指(その音符のピッチが割り当てられた鍵の押鍵に使うべき指)の修正が望ましいような場合、判定はYESとなってステップSH6に移行し、そうでない場合には、判定はNOとなり、ステップSH5で変数meの値をインクリメントしてから上記ステップSH3に戻る。それにより、修正すべき箇所の特定を継続させる。
ステップSH6では、変数metに変数meの値を代入し、変数meの値が変数me_eの値未満ならば変数meの値に1を加算した値、そうでなければ変数meの値を変数melに代入し、変数cntに1を代入する。次のステップSH7では、変数metの値が0、またはME[met].tendが0か否か判定する。変数metの値で指定される音符が曲の先頭、または極点(データtendが0)に位置する音符であった場合、判定はYESとなってステップSH9に移行する。そうでない場合には、判定はNOとなり、ステップSH8で変数metの値をデクリメントすると共に、変数cntの値をインクリメントしてから再度ステップSH7での判定を行う。なお、各音符データME中のデータtendは、例えば図3に示すメインルーチン内のステップSA3において、音符間のピッチ差を算出し参照して設定するようになっている。
ステップSH9では、変数cntの値が定数RETRYN未満か否か判定する。その値が定数RETRYN未満であった場合、判定はYESとなってステップSH10に移行する。そうでない場合には、判定はNOとなり、ステップSH12で変数me_topに変数metの値、変数me_tailに変数melの値をそれぞれ代入した後、一連の処理を終了する。
ステップSH10では、変数melの値が変数me_e、またはME[mel].tendが0か否か判定する。変数melの値で指定される音符が区間の最後、または極点に位置する音符であった場合、判定はYESとなってステップSH12に移行する。そうでない場合には、判定はNOとなり、ステップSH11で変数mel、及びcntの各値をインクリメントしてから再度ステップSH10での判定を行う。
このようにして本実施の形態では、修正すべきと見なす箇所は、その前後の部分を含めて修正するようにしている。これは、1箇所の修正はその前後の演奏に影響を及ぼすのが普通であり、また、その箇所に至る部分の演奏を考慮しなければよりコストの低い運指を設定するのは困難、といった理由からである。定数RETRYNは、そのように修正対象範囲を設定することから、その範囲が必要以上に広がらないように用意している。
次に、図6、及び図7に示す指定区間運指生成処理内でステップSJ25として実行される同一フレーズ補正処理について、図27、及び図28に示すそのフローチャートを参照して詳細に説明する。その補正処理は、同一の(同一と見なせる)フレーズを検出し、そのなかでコストが最小のフレーズを抽出し、抽出したフレーズで設定されている運指を他のフレーズに適用させて補正する処理である。
演奏内容が同一のフレーズであっても、その前、或いは後に位置するフレーズの影響によって運指(の組み合わせ)が異なることがありうる。その運指の違いは特に初心者に対しては違和感を与える可能性がある。本実施の形態では、そのような違和感を与えない運指情報を生成できるようにするために、同一フレーズ補正スイッチを設け、そのスイッチへの操作によりこの同一フレーズ補正処理を実行させるか否かユーザが選択できるようにさせている。
先ず、ステップSX1では、変数pidに1を代入する。続くステップSX2では、変数meに変数me_sの値、変数cosbestには−1をそれぞれ代入する。その次に移行するステップSX3では、変数meの値を順次、インクリメントしながら、その値で指定される音符データME[me]中のデータpid、及びpstatを確認していくことにより、データpid、及びpstatが共に0である最初の音符データMEを指定するインデックス値を変数me_topに、その後に確認される、データpidが0でデータpstatが2の音符データMEを指定するインデックス値を変数me_tailにそれぞれ代入するための処理を行う。ステップSX4にはその後に移行する。
データpid、及びpstatが共に0である音符データMEは分割したフレーズの先頭に位置し、データpidが0でデータpstatが2の音符データMEはそのフレーズの最後に位置する。ステップSX4では、変数meの値が変数me_eと一致するまでに、そのような音符データMEのインデックス値を代入することによるフレーズの検出が行えたか否か判定する。ステップSX3で2つのインデックス値の代入が行えた場合、判定はYESとなってステップSX5に移行し、そうでない場合には、判定はNOとなって図28のステップSX12に移行する。
ステップSX5では、変数costbestの値が−1か否か判定する。その値が−1であった場合、判定はYESとなり、ステップSX6で変数mebestに変数me_topの値を代入してからステップSX8に移行する。そうでない場合には、判定はNOとなり、ステップSX7に移行して、今回、検出したフレーズが、変数mebestに先頭位置の音符データMEのインデックス値が代入されたフレーズと同じか否か判定する。それらのフレーズが同一のものであった場合、判定はYESとなってステップSX8に移行する。そうでない場合には、判定はNOとなって上記ステップSX3に戻る。
フレーズが同一か否かの判定は、特に詳細な説明は省略するが、例えば隣り合う音符間のピッチ差、押鍵すべき鍵の種類に着目して行っている。当然のことながら、別の内容に着目して判定を行うようにしても良い。
ステップSX8では、ME[me_top].pidとして変数pidの値をセットする。次のステップSX9では、図20に示す区間コスト算出処理を実行する。その次に実行するステップSX10では、変数costbestの値が−1、または変数costtmpの値が変数costbestの値未満か否か判定する。変数costbestの値が−1、または変数costtmpの値が変数costbestの値未満であった場合、判定はYESとなり、ステップSX11で変数costbestに変数costtmpの値、変数mebestに変数me_topの値をそれぞれ代入した後、上記ステップSX3に戻る。そうでない場合には、変数costbestの値が−1でなく、かつ変数costtmpの値が変数costbestの値より大きい場合には、判定はNOとなって上記ステップSX3に戻る。
このようにして、本実施の形態では、分割したフレーズのなかで同一の(同一と見なす)フレーズには同一のフレーズ番号を割り当て、同一のフレーズのなかでコストが最小のフレーズを特定し、特定したフレーズの先頭に位置する音符データMEのインデックス値を変数mebestに代入している。図28のステップSX12には、そのようなフレーズ番号の割り当て、コストが最小のフレーズの特定を試みた後に移行する。
そのステップSX12では、変数costbestの値が−1、または変数costbestの値が定数MAXCOSTと等しいか否か判定する。変数costbestの値としての−1は、対象となるフレーズ自体が検出されなかったことを意味する。定数MAXCOSTは、他のフレーズに運指を適用させるフレーズのコストがその適用を行うべきレベルか否か判定するために用意したものである。このようなことから、結果として、運指を適用するフレーズが存在しない場合には、判定はYESとなってステップSX18に移行し、そうでない場合には、判定はNOとなってステップSX13に移行する。
ステップSX13では、変数meに変数me_sの値を代入する。続くステップSX14では、上記ステップSX3と同様にして、データpidが変数pidの値でデータpstatが0である最初の音符データMEを指定するインデックス値を変数me_topに、その後に確認される、データpidが変数pidの値でデータpstatが2の音符データMEを指定するインデックス値を変数me_tailにそれぞれ代入するための処理を行う。ステップSX15にはその後に移行する。
ステップSX15では、変数meの値が変数me_eと一致するまでに、そのような音符データMEのインデックス値を代入することによるフレーズの検出が行えたか否か判定する。ステップSX14で2つのインデックス値の代入が行えた場合、判定はYESとなってステップSX16に移行し、そうでない場合には、判定はNOとなってステップSX18に移行する。
ステップSX16では、変数me_topの値が変数mebestの値と等しいか否か判定する。それらの値が等しい場合、つまり変数me_topの値として代入されたインデックス値は運指を適用させる元のフレーズの先頭に位置する音符データMEを指定するものであった場合、判定はYESとなって上記ステップSX14に戻る。そうでない場合には、判定はNOとなってステップSX17に移行し、コストが最小のフレーズで設定された運指を適用させるためのコピーを行う。そのコピーは、変数p1に変数me_topの値から変数me_tailの値まで順次、代入しながら、その変数p1の値で指定される音符データME[p1]のデータfigとして、初期値が変数mebestの値でその値から変数p1の値と同じタイミングで順次インクリメントする変数p2の値で指定される音符データME[p2]のデータfigを設定(つまりME[p1].fig←ME[p2].fig)することで行われる。そのようにして適用を行った後は上記ステップSX14に戻る。
上記ステップSX12の判定がYES、或いはSX15の判定がNOとなって移行するステップSX18では、変数pidの値をインクリメントする。続くステップSX19では、変数pidの値が定数MAXPIDと等しいか否か判定する。その値が定数MAXPIDと等しい場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなって図27のステップSX2に戻る。
図6、及び図7に示す指定区間運指生成処理では、上述したようなサブルーチン処理が実行される。そのようなサブルーチン処理を変数loopcntの値に応じて実行することから、その値をインクリメントさせながら指定区間運指生成処理を実行させる度に、運指情報はより最適化されていくこととなる。
図29は、図5に示す運指生成処理内でステップSB3として実行される評価処理のフローチャートである。最後に図29を参照して、その評価処理について詳細に説明する。その評価処理では、上述したように、運指コストとして、1音符平均のコストを算出し、算出したコストが定数THRCOST2より小さければ、生成、或いは修正した運指情報は適切なものであるとして変数loopcntに0を代入するようになっている。
先ず、ステップSW1では、変数me_topに変数me_sの値、変数me_tailに変数me_sの値をそれぞれ代入し、それに続くステップSW2で図20に示す区間コスト算出処理を実行する。その次に移行するステップSW3では、変数costtmpの値が定数THRCOST2未満か否か判定する。その定数THRCOST2は、生成された運指情報が最適(適切)なものか否か判定するために用意した閾値である。このことから、その運指情報が最適なものであった場合、判定はYESとなり、ステップSW4で変数loopcntに0を代入した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
図5の運指生成処理では、ステップSB4の判定がNO、つまり変数loopcntの値が0となるまでステップSB2〜SB4で形成される処理ループを繰り返し実行する。その繰り返しを必要に応じて行わせることにより、ステップSB2の指定区間運指生成処理によって最初に生成された運指情報は、それ以降の生成処理の実行により、より最適(適切)な運指情報となるまで段階的に順次、補正されていくことになる。
なお、本実施の形態では、変数loopcntの値に応じた運指情報の生成は一つの内容にのみ着目して行うようにしているが(図6、及び図7)、複数の内容に着目して行うようにしても良い。着目する内容、その順序は演奏データ、或いは運指情報を参照して決定するようにしても良い。
上述したような運指情報生成装置を実現させるようなプログラムは、CD−ROM、DVD、或いは着脱自在なフラッシュメモリ等の記録媒体に記録させて配布しても良い。公衆網等の通信ネットワークを介して、そのプログラムの一部、若しくは全部を配信するようにしても良い。そのようにした場合には、ユーザーはプログラムを取得してデータ処理装置にロードすることにより、その装置に本発明を適用させることができる。このことから、記録媒体は、プログラムを配信する装置がアクセスできるものであっても良い。