楽曲構造解析装置、及びプログラム
【課題】 繰り返し構造に着目した楽曲の分割を常に適切に行うための技術を提供する。
【解決手段】 楽曲の分割、つまり関連付けるべきフレーズの抽出は、始めに先頭の音符が所定数以上、一致する部分をマーキングした後、マーキングした部分以降に一致している部分を確認していくことで行う。それにより、楽曲のなかで演奏内容が類似性を有する部分を抽出する。
【解決手段】 楽曲の分割、つまり関連付けるべきフレーズの抽出は、始めに先頭の音符が所定数以上、一致する部分をマーキングした後、マーキングした部分以降に一致している部分を確認していくことで行う。それにより、楽曲のなかで演奏内容が類似性を有する部分を抽出する。
【発明の詳細な説明】
【技術分野】
【0001】
本発明は、楽曲の演奏内容を音符単位で示す演奏情報を参照して、その楽曲の構造解析を行うための技術に関する。
【背景技術】
【0002】
従来、楽曲の構造解析を行う楽曲構造解析装置としては、例えば特許文献1に記載されたものがある。その特許文献1に記載された楽曲構造解析装置では、音符の発音時間である音符長の変化に着目して、楽曲の分割を行うようにしている。
【0003】
音符長の変化に着目することにより、楽曲全体を部分的な複数の演奏区間に分割することができる。しかし、そのような分割が、確認を望む構造の確認が容易なように常に適切に行えるとは限らない。むしろ、その分割を常に適切に行うためには、確認したい構造に着目して行うのが望ましいと言える。その構造として、類似する演奏内容の演奏が異なる複数の部分で行われる繰り返し構造も重要なものの一つであると考えられる。
【特許文献1】特開2002−132255号公報
【発明の開示】
【発明が解決しようとする課題】
【0004】
本発明の課題は、繰り返し構造に着目した楽曲の分割を常に適切に行うための技術を提供することにある。
【課題を解決するための手段】
【0005】
本発明の楽曲構造解析装置は、楽曲の構造の解析を行うことを前提とし、楽曲の演奏内容を音符単位で示す演奏情報を取得する演奏情報取得手段と、演奏情報取得手段が取得した演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、楽曲から演奏内容が類似する複数の演奏区間を抽出する構造解析手段と、を具備する。
【0006】
なお、上記構造解析手段は、音符による発音時間の相違を考慮して解析を行う、ことが望ましい。また、演奏区間として抽出されない部分に存在する音符のなかで所定の条件を満たす音符は該演奏区間に含める、ことが望ましい。
【0007】
本発明のプログラムは、上記楽曲構造解析装置が具備する手段を実現させるための機能を搭載している。
【発明の効果】
【0008】
本発明は、楽曲の演奏内容を音符単位で示す演奏情報を取得し、その演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、楽曲から演奏内容が類似する複数の演奏区間を抽出する。そのように演奏内容が類似性(関連性)を有する演奏区間を抽出することにより、楽曲の繰り返し構造が容易に確認できるようになる。このため、その繰り返し構造を通して、フレーズ構造の確認も容易に行えるようになる。
【発明を実施するための最良の形態】
【0009】
以下、本発明の実施の形態について、図面を参照しながら詳細に説明する。
<第1の実施の形態>
図1は、第1の実施の形態による楽曲構造解析装置の構成を説明する図である。
【0010】
その楽曲構造解析装置は、図1に示すように、装置全体の制御を行うCPU101と、そのCPU101がワークに用いるRAM102と、CPU101が実行するプログラムや各種制御用データを格納したROM103と、例えば各種キー等の操作子を有するキーボードやポインティングデバイス等である入力装置104と、例えば液晶表示装置である表示装置105と、外部装置との間でデータの入出力を行うインターフェース(I/F)106と、を備えて構成されている。
【0011】
上記I/F106は、例えば光ディスク装置や光磁気ディスク装置などの記録媒体駆動装置との間でデータの入出力を行うものか、或いは通信ネットワークを介した通信を行う通信制御装置である。ここでは、前者であるとの前提で説明を行うことにする。
【0012】
上述したような構成の楽曲構造解析装置は、例えばパーソナルコンピュータ(PC)、或いはPDAといったデータ処理装置である。その解析装置は、後述するような動作を行わせるプログラム(アプリケーション・プログラム。以降「アプリケーション」と略記)をCPU101に実行させることで実現される。ここでは便宜的に、そのアプリケーションはROM103に格納されていることとする。
【0013】
そのアプリケーションは、楽曲の演奏内容を示す楽曲データを参照し、その楽曲データが示す部分的な演奏内容の類似性に着目した構造解析を行い、演奏内容が類似すると見なす演奏区間を楽曲から抽出する。それにより、他に類似するものが存在する演奏区間とそうでない部分(演奏区間)とに大別する。
【0014】
そのように演奏内容が類似する演奏区間を抽出することにより、楽曲の繰り返し構造が容易に確認できるようになる。その繰り返し構造を通して、フレーズ構造の確認も容易に行えるようになる。演奏を行っていく際の指の運びである運指を示す運指情報の生成では、例えば演奏内容が同一の演奏区間ではその前後の部分に係わらずに同一の運指情報の生成を行えるようになる。それにより、演奏内容が同じでありながら前、或いは後の部分の違いによって運指が異なることに違和感を覚えるような人に対しては、違和感を与えないような運指情報を生成できることとなる。演奏区間の抽出は、その演奏区間に存在する音符をグループ化することに相当する。その演奏区間については以降「フレーズ」と呼ぶことにする。
【0015】
図2は、上記楽曲データの構成を説明する図である。
その楽曲データは、I/F106を介して読み込まれ、RAM102に格納される。楽曲の演奏内容を音符単位で示すデータ(以降「音符データ」と呼ぶ)の集合体として構成されている。図中に括弧を付して表記の「Note」はその音符データを表している。括弧内の数値は、音符データを指定するインデックス(値)である。以降、インデックスが判明している音符データには「Note」、及びそれに続けて括弧内にインデックスを示す数値、或いは変数のシンボルを表記したものを付して例えば「音符データNote[0]」といったように記載し、そのインデックスが判明していない音符データには単に「Note」を付して記載することとする。これは他でも同様である。
【0016】
その音符データNoteは、「iTime」と表記の発音開始ティック(時刻)、「iGate」と表記のゲートタイム(発音継続時間)、「Pitch」と表記のピッチ(ノート番号)、「pParent」と表記の当該音符データNoteが属するグループの先頭に位置する音符データNoteのインデックス、「pStart」と表記のそのグループと演奏内容が類似しているとして関連付けられた他のグループの先頭に位置する音符データNoteのインデックス、「iStatus」と表記のグループ化された状態を示すフラグ、「pNext」と表記の次に処理対象となる音符データNoteのインデックス、及び「pRev」と表記の前に処理対象となる音符データNoteのインデックス、の各データを備えた構成となっている。それらのなかで、データiTime、iGate、Pitch、pNext、及びpRevはI/F106を介して読み込んだ楽曲データを構成するデータか、或いはそれから生成されるデータである。
【0017】
グループ間の対応関係を管理するために、本実施の形態では、図3に示すフレーズデータを生成しRAM102に確保した領域に保存するようにしている。図中に括弧を付して表記の「Phrase」はそのフレーズデータを表している。括弧内の数値は、フレーズデータを指定するインデックス(値)である。以降、同様にインデックスが判明しているフレーズデータには「Phrase」、及びそれに続けて括弧内にインデックスを示す数値、或いは変数のシンボルを表記したものを付して記載することとする。
【0018】
そのフレーズデータPhraseは、「pOrgParent」と表記の大元となるグレープの先頭に位置する音符データNoteのインデックス、「pStart」と表記の対応するグループの先頭に位置する音符データNoteのインデックス、「iNoteCnt」と表記のグループに属する音符データNote数、「ITotalTick」と表記のグループの総演奏時間(合計時間)、「pNextGroup」と表記の次のグループデータPhraseのインデックス、の各データを備えた構成となっている。
【0019】
以降は、図4〜図9に示す各種処理のフローチャート、及び図10に示す説明図を参照しつつ、楽曲構造解析装置の動作について詳細に説明する。
図4は、構造解析処理のフローチャートである。始めに図4を参照して、その解析処理について詳細に説明する。その解析処理は、CPU101がROM103に格納されたアプリケーションを実行することで実現される。
【0020】
そのアプリケーションは起動されると、先ず、ステップSA1で各種データ(変数を含む)の初期化を行う。続くステップSA2では、例えばI/F106により記録媒体駆動装置にセットされた記録媒体から楽曲データの読み込みを行い、図2に示すようなデータ構成でRAM102に格納する。その後に移行するステップSA3では、楽曲をフレーズ(類似するものが他に存在するフレーズ)に分割するフレーズ分割処理を実行する。一連の処理はその後に終了する。
【0021】
図5は、上記ステップSA3として実行されるフレーズ分割処理のフローチャートである。次にその分割処理について、図5に示すそのフローチャートを参照して詳細に説明する。
【0022】
先ず、ステップSB1では、楽曲データを構成する各音符データNoteのデータpParent、pStartにNULL(値としては0である)を代入する。次のステップSB2では、変数pRefNoteに、楽曲データの先頭に位置する音符データNoteのインデックスを代入し、変数pRefLastに、その音符データNoteから定数MarkingNotesだけ先の音符データNoteのインデックス値を代入する。ステップSB3にはその後に移行する。定数MarkingNotesは、グループと見なさない最小の音符数として定義したものである。
【0023】
ステップSB3では、変数pRefLastの値で指定される音符データNote(図中「Note[pRefLast]」と表記。以降、その表記法も用いることにする。これは他でも同様である)のデータpNextの値がNULLでないか否か判定する。その値がNULLであった場合、つまりその音符データNoteが最後のものであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSB4に移行する。
【0024】
ステップSB4では、変数pRefNoteの値で指定される音符データNoteのデータpStartの値がNULLか否か判定する。その音符データNoteがグループ化されていない場合、その値はNULLであることから、判定はYESとなり、ステップSB5で変数iMarkCntに0を代入し、更にステップSB6で関連付けるグループの先頭位置を検索するための先頭位置検索処理を実行してからステップSB7に移行する。そうでない場合には、判定はNOとなってステップSB9に移行する。
【0025】
上記変数iMarkCntは、検索により抽出した先頭位置の数を計数するためのものである。ステップSB7では、その値が0でないか否か判定する。その先頭位置が抽出された場合、その値は0より大きい値に更新されることから、判定はYESとなり、ステップSB8でグループ化処理を実行し、次のステップSB9で変数pRefNoteに、変数pRefNoteの値で指定される音符データNoteのデータpNextの値、変数pRefNoteに、その音符データNoteから定数MarkingNotesだけ先の音符データNoteのデータpNextの値を代入してから上記ステップSB3に戻る。そうでない場合には、判定はNOとなり、次にそのステップSB9に移行する。
【0026】
このようにして、フレーズ分割処理では、変数pRefNoteの値を順次、更新しながら、その値で指定される音符(音符データNote)が先頭位置に存在するグループ(フレーズ)を大元のグループとして、そのグループと関連付けられる他のグループを探すようになっている。その他のグループが探し出せた場合、大元のグループ、及びその他のグループの登録を行っている。
【0027】
次に、上記ステップSB6として実行される先頭位置検索処理について、図6に示すそのフローチャートを参照して詳細に説明する。
先ず、ステップSC1では、変数pLookupNoteにNote[pRefLast].pNext(変数pRefLastの値で指定される音符データNoteのデータpNext)の値を代入する。次のステップSC2では、変数pLookupNoteの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLでない場合、判定はYESとなってステップSC5に移行する。そうでない場合には、判定はNOとなってステップSC3に移行する。
【0028】
ステップSC3では、変数iMarkCntの値が0より大きいか否か判定する。その値が0より大きい場合、判定はYESとなってステップSC4に移行し、フレーズデータPhraseの登録を行うためのフレーズデータの登録処理を実行した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
【0029】
ステップSC5では、変数jdgに論理値TRUEを代入する。続くステップSC6では、変数iに定数MarkingNotesを代入する。その次のステップSC7では、変数pNotetmpに変数pLookupNoteの値、変数pReftmpに変数pRefNoteの値をそれぞれ代入する。その後に移行するステップSC8では、変数jdgの値がTRUEであり、且つ変数iの値が0より大きいか否か判定する。変数jdgの値がTRUEであり、且つ変数iの値が0より大きい場合、判定はYESとなってステップSC9に移行する。そうでない場合には、つまり変数jdgの値がFALSEか、或いは変数iの値が0以下であった場合には、判定はNOとなってステップSC16に移行する。
【0030】
ステップSC9では、変数pRefNoteの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLでない場合、つまりそれ以降の音符データNoteが存在しない場合、判定はYESとなってステップSC10に移行する。そうでない場合には、判定はNOとなり、ステップSC15で変数jdgにFALSEを代入し、更にステップSC14で変数iの値をデクリメント(図中「−−」と表記)してから上記ステップSC8に戻る。
【0031】
ステップSC10では、変数jdgの値がTRUEであり、且つNote[pReftmp].Pitchの値とNote[pNotetmp].Pitchの値が等しければ(変数pReftmp、pNotetmpの各値で指定される音符のピッチが等しければ)TRUEを代入する。そうでなければFALSEを代入する。続くステップSC11では、変数jdgの値がTRUEであり、且つNote[pNotetmp].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pReftmp].ITimeの値からNote[pRefNote].ITimeの値を引いて得られる値が定数StartTickRange未満であれば(それら発音開始ティックの時間間隔の差が定数StartTickRangeとして用意した閾値未満であれば)TRUEを代入する。そうでなければFALSEを代入する。その次のステップSC12では、変数jdgの値がTRUEであり、且つNote[pReftmp].IGateの値をNote[pNotetmp].IGateの値で割った値を1から引いた値の絶対値が定数IGateTimeRatio未満であれば(それらのゲートタイム比が許容範囲内であれば)TRUEを代入する。そうでなければFALSEを代入する。その後は、ステップSC13において、変数pNotetmpにNote[pNotetmp].pNextの値、変数pReftmpにNote[pReftmp].pNextの値をそれぞれ代入してからステップSC14に移行する。
【0032】
このようにして、本実施の形態では、音符のピッチが等しい、発音開始ティック間の時間間隔の差が許容範囲内、ゲートタイム比が許容範囲内、という条件を全て満たしていなければ変数jdgにはFALSEを代入するようにしている。それにより、抽出する先頭位置としては、それらの条件を音符毎に全て満足する音符数が定数MarkingNotes以上となっている音符群を対象にしている。その対象となる条件については便宜的に「フレーズ成立条件」と呼び、音符毎に満足すべき全ての条件については「音符成立条件」と呼ぶことにする。フレーズ成立条件は、定数MarkingNotes以上、連続して音符成立条件が満たされた場合に満たすことになる。
【0033】
上記ステップSC8の判定がNOとなって移行するステップSC16では、変数jdgの値がTRUEか否か判定する。その値がTRUEであった場合、つまりフレーズ成立条件を満たす、抽出すべき先頭位置が抽出できた場合、判定はYESとなり、ステップSC18でNote[pLookupNote].pParentに変数pRefNoteの値を代入し、ステップSC19で変数iMarkCntの値をインクリメント(図中「++」と表記)し、更にステップSC20で変数pLookupNoteにNote[pNotetmp].pNextの値を代入してから上記ステップSC2に戻る。そうでない場合には、判定はNOとなり、ステップSC17で変数pLookupNoteにNote[pLookupNote].pNextの値を代入してから上記ステップSC2に戻る。
【0034】
このようにして、変数pRefNoteの値で指定される音符(音符データNote)を大元のフレーズの先頭位置と想定し、そのフレーズとフレーズ成立条件を満たす各フレーズの先頭位置の音符データNoteにデータpParentとして変数pRefNoteの値をそれぞれ設定するようにしている。その設定により、先頭位置の音符をマーキングしている。
【0035】
図7は、上記ステップSC4として実行されるフレーズデータの登録処理のフローチャートである。次に図7を参照して、その登録処理について詳細に説明する。
先ず、ステップSD1では、変数iPに0を代入する。続くステップSD2では、その変数iPの値で指定されるフレーズデータPhraseのデータpOrgParentの値がNULLか否か判定する。その値がNULLでない場合、判定はNOとなり、ステップSD3で変数iPの値をインクリメントしてから、再度ステップSD2の判定処理を行う。そうでない場合には、判定はYESとなってステップSD4に移行し、Phrase[iP].pOrgParent、及びPhrase[iP].pStartとして変数pRefNoteの値、Phrase[iP].iNoteCntとして定数MarkingNotes、Phrase[iP].ITotalTickとして、Note[pRefLast].ITimeの値にNote[pRefLast].IGateの値を加算した値からNote[pRefNote].ITimeの値を引いて得られる値(定数MarkingNotes分の総演奏時間)をそれぞれ代入する。一連の処理はその後に終了する。
【0036】
図8は、図5に示すフレーズ分割処理内でステップSB8として実行されるグループ化処理のフローチャートである。次にそのグループ化処理について、図8を参照して詳細に説明する。
【0037】
先ず、ステップSF1では、変数pLookupNoteにNote[pRefLast].pNextの値を代入する。次のステップSF2では、変数pLookupNoteの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLでない場合、判定はYESとなってステップSF3に移行する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
【0038】
ステップSF3では、変数pLookupNoteの値で指定される音符データNoteのデータpParentの値が変数pRefNoteの値と等しいか否か判定する。それらの値が等しくない場合、判定はNOとなり、ステップSF4で変数pLookupNoteにNote[pRefLast].pNextの値を代入した後、上記ステップSF2に戻る。そうでない場合には、判定はYESとなってステップSF5に移行する。それにより、関連付けられるフレーズの先頭位置としてマーキングされた音符の抽出を行う。
【0039】
ステップSF5では、変数pNotetmpに変数pLookupNoteの値、変数pReftmpに変数pRefNoteの値をそれぞれ代入する。次のステップSF6では、変数jdgにTRUEを代入する。その後は、ステップSF7で変数iに1を代入してからステップSF8に移行する。
【0040】
ステップSF8では、変数jdgの値がTRUEであり、且つ変数pNotetmpの値で指定される音符データNoteのデータpNextの値がNULLか否か判定する。変数jdgの値がTRUEでないか、或いはそのデータpNextの値がNULLであった場合、判定はNOとなってステップSF14に移行する。そうでない場合には、判定はYESとなってステップSF9に移行する。
【0041】
ステップSF9〜SF12では、図6に示すステップSC10〜SC13と同様の処理が行われる。ステップSF12の処理の実行後は、ステップSF13に移行して、変数iの値をインクリメントしてから上記ステップSF8に戻る。それにより、連続して音符成立条件を満たす音符数のカウントを継続させる。
【0042】
上記ステップSF8の判定がNOとなって移行するステップSF14では、変数iの値が定数MarkingNotesより大きいか否か判定する。その値が定数MarkingNotes以下であった場合、判定はNOとなり、ステップSF15でNote[pLookupNote].pParentとしてNULLを設定し、ステップSF16で変数pLookupNoteにNote[pLookupNote].pNextの値を代入してから上記ステップSF2に戻る。一方、そうでない場合には、つまり変数iの値が定数MarkingNotesより大きい場合には、判定はYESとなってステップSF17に移行する。
【0043】
ステップSF17では、フレーズデータ間の関連付けを行いつつ、フレーズデータの登録を行うフレーズデータへのグループ登録処理を実行する。続くステップSF18では、変数pNoteRsltに変数pLookupNoteの値を代入する。その後はステップSF19に移行する。
【0044】
ステップSF19では、変数pNotetmpの値が変数pNoteRsltの値と等しくないか否か判定する。それらの値が等しい場合、判定はNOとなってステップSF16に移行する。そうでない場合には、判定はYESとなり、ステップSF20でNote[pNoteRslt].pStartに変数pLookupNoteの値、Note[pNoteRslt].pParentに変数pRefNoteの値をそれぞれ代入し、次のステップSF21で変数pNoteRsltにNote[pNoteRslt].pNextの値を代入してから上記ステップSF19に戻る。それにより、大元のフレーズと関連付けられたフレーズを構成する各音符データNoteのデータpStartとして、その大元のフレーズの先頭位置の音符データNoteを指定する値が設定される。データpParentとしては、属するフレーズの先頭位置の音符データNoteを指定する値が設定される。
【0045】
図10は、楽曲の分割方法を説明する図である。
楽曲の分割、つまり関連付けるべきフレーズの抽出は、図10に示すように、始めに先頭位置検索により、先頭部分の音符が全て音符成立条件を満たすフレーズの先頭位置の音符に対してマーキングを行い、その後、音符成立条件を満たさなくなるまでの範囲をフレーズの範囲として再度、特定(検索)することで行われる。先頭位置の音符に対するマーキングは、図6に示す先頭位置検索処理の実行により行われ、再度の検索はグループ化処理を実行することで行われる。
【0046】
図9は、上記ステップSF17として実行されるフレーズデータへのグループ登録処理のフローチャートである。最後に図9を参照して、その登録処理について詳細に説明する。
【0047】
先ず、ステップSE1では、変数iPに0を代入する。続くステップSE2では、その変数iPの値で指定されるフレーズデータPhraseのデータpOrgParentの値が変数pRefNoteの値と等しいか否か判定する。それらの値が一致する場合、判定はYESとなってステップSE6に移行する。そうでない場合には、判定はNOとなってステップSE3に移行する。
【0048】
ステップSE3では、変数iPの値で指定されるフレーズデータPhraseのデータpOrgParentの値がNULLか否か判定する。その値がNULLでない場合、判定はNOとなり、ステップSE4で変数iPの値をインクリメントしてから上記ステップSE2に戻る。そうでない場合には、判定はYESとなってステップSE5に移行し、Phrase[iP].pOrgParentとして変数pRefNoteの値、Phrase[iP].pStartとして変数pLookupNoteの値、Phrase[iP].iNoteCntとして変数iの値、Phrase[iP].ITotalTickとして、Note[pNotetmp].ITimeの値にNote[pNotetmp].IGateの値を加算した値からNote[pLookupNote].ITimeの値を引いて得られる値(フレーズ全体での総演奏時間)をそれぞれ代入する。一連の処理はその後に終了する。
【0049】
上記ステップSE2の判定がYESとなって移行するステップSE6では、Phrase[iP].iNoteCntの値が変数iの値未満か否か判定する。変数iPの値で指定されるフレーズの音符数が変数iの値以上であった場合、判定はNOとなってステップSE3に移行する。そうでない場合には、判定はYESとなってステップSE7に移行し、Phrase[iP].iNoteCntとして変数iの値、Phrase[iP].ITotalTickとして、Note[pReftmp].ITimeの値にNote[pReftmp].IGateの値を加算した値からNote[pRefNote].ITimeの値を引いて得られる値をそれぞれ代入する。また、変数pRefNoteの値で指定される音符データNoteから変数iの値分の音符データNoteに対し、データpParent、pStartとして変数pRefNoteの値をそれぞれ設定する。一連の処理はその後に終了する。
【0050】
このようにして、本実施の形態では、関連付けたフレーズ間で総演奏時間が異なる場合、フレーズのなかで最も長い総演奏時間のものを各フレーズの総演奏時間とさせている。それにより、基本的には同じと見なすべきフレーズのなかで最後を他と変化させたようなものはその変化させた部分の存在を過大に評価しないようにさせている。
<第2の実施の形態>
上記第1の実施の形態では、音符を一対一に対応付けてフレーズ間の対比を行っている。これに対し、第2の実施の形態は、音符長を考慮してフレーズ間の対比を行うようにしたものである。
【0051】
楽曲では、実質的には同じフレーズであってもその一部を変更させることがある。具体的には、発音される楽音を複数の楽音に置き換えたり(分割)、或いはその逆に、複数の楽音をまとめて1つの楽音とさせたり(結合)することがある。このようなことから、第2の実施の形態では、そのような分割や結合にも適切に対応できるように、音符長を考慮したフレーズ間の対比を行うようにしている。
【0052】
第2の実施の形態における楽曲構造解析装置の構成は、基本的に第1の実施の形態におけるそれと同じである。動作も大部分は同じか、或いは基本的に同じである。このことから、第1の実施の形態で付した符号をそのまま用いて、第1の実施の形態から異なる部分についてのみ説明する。
【0053】
第2の実施の形態では、図8に示すグループ化処理において、ステップSF7〜SF10間が第1の実施の形態から異なっている。このことから、その異なる部分について、図11に示すフローチャートを参照して詳細に説明する。
【0054】
第2の実施の形態では、ステップSF7から移行するステップSF8の判定がYESとなると、次にステップSG1に移行して、変数TickDifに、Note[pNotetmp].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pReftmp].ITimeの値からNote[pRefNote].ITimeの値を引いた値を減算して得られる値(フレーズ間における、異なる音符間の発音開始ティックの時間間隔の差)を代入する。その後に移行するステップSG2では、変数TickDifの値が定数StartTickRangeより大きいか否か判定する。その値が定数StartTickRangeより大きい場合、つまり関連付けされるフレーズのほうが大元のフレーズより時間間隔が無視できない差で長い場合、判定はYESとなってステップSG4に移行し、そうでない場合には、判定はNOとなってステップSG3に移行する。
【0055】
ステップSG3では、変数TickDifの値が負の値の定数StartTickRangeより小さいか否か判定する。その値が負の値の定数StartTickRangeより小さい場合、つまり関連付けされるフレーズのほうが大元のフレーズより時間間隔が無視できない差で短い場合、判定はYESとなってステップSG10に移行し、そうでない場合には、判定はNOとなってステップSF9に移行する。
【0056】
上記ステップSG4では、変数pNoteSkipに、Note[pReftmp].pNextの値を代入する。次のステップSG5では、Note[pNotetmp].ITimeの値が、Note[pNoteSkip].ITimeの値より大きいか否か判定する。前者が後者以下であった場合、判定はNOとなってステップSG3に移行する。そうでない場合には、判定はYESとなってステップSG6に移行する。
【0057】
ステップSG6では、変数TickDif2に、Note[pNotetmp].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pNoteSkip].ITimeの値からNote[pRefNote].ITimeの値を引いた値を減算して得られる値を代入する。その後に移行するステップSG7では、変数TickDifの値の絶対値が定数StartTickRangeより小さいか否か判定する。その絶対値が定数StartTickRangeより小さい場合、つまり2つのフレーズ間における時間間隔の差が許容範囲内であった場合、判定はYESとなり、ステップSG9で変数nReftmpに変数pNoteSkipの値を代入した後、ステップSG3に移行する。そうでない場合には、判定はNOとなってステップSG8に移行し、変数pNoteSkipにNote[pNoteSkip].pNextの値を代入する。その後はステップSG5に戻る。それにより、大元のフレーズ側で着目する音符を先に進めることで時間的な調整が可能か否かの確認を再度、行う。そのような確認により、例えば大元のフレーズでは2個の八分音符が存在する演奏区間に、関連付けられるフレーズでは1個の四分音符が存在しているのであれば、2個の八部音符を1個の四分音符と対応付けて両者の演奏時間は対比されることとなる。
【0058】
ステップSG3の判定がYESとなって移行するステップSG10では、変数iSkipに1を代入する。続くステップSG11では、変数pNoteSkipにNote[pNotetmp].pNextの値を代入する。その後はステップSG12に移行して、Note[pNoteSkip].ITimeの値が、Note[pNoteSkip].ITimeの値より大きいか否か判定する。前者が後者以下であった場合、判定はNOとなってステップSG9に移行する。そうでない場合には、判定はYESとなってステップSG13に移行する。
【0059】
ステップSG13では、変数TickDif2に、Note[pNoteSkip].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pReftmp].ITimeの値からNote[pRefNote].ITimeの値を引いた値を減算して得られる値を代入する。その後に移行するステップSG14では、変数TickDifの値の絶対値が定数StartTickRangeより小さいか否か判定する。その絶対値が定数StartTickRangeより小さい場合、つまり2つのフレーズ間における時間間隔の差が許容範囲内であった場合、判定はYESとなってステップSG17に移行する。そうでない場合には、判定はNOとなり、ステップSG15で変数iSkipの値をインクリメントし、ステップSG16で変数pNoteSkipにNote[pNoteSkip].pNextの値を代入する。その後はステップSG12に戻る。それにより、大元のフレーズと関連付けられるフレーズ側で着目する音符を先に進めることで時間的な調整が可能か否かの確認を再度、行う。
【0060】
ステップSG17では、変数iSkipの値が0より大きいか否か判定する。その値が0より大きい場合、判定はYESとなり、ステップSG18でNote[pNotetmp].iStatusとして1を設定し、ステップSG19で変数pNotetmpにNote[pNotetmp].pNextの値を代入し、更にステップSG20で変数iSkipの値をデクリメントしてからステップSG17に戻る。それにより、大元のフレーズ側で該当する音符が存在しない音符の全てにデータiStatusとして1を設定する。
<第3の実施の形態>
上記第1、及び第2の実施の形態では、基本的に、音符成立条件が満足しなくなったところでフレーズの範囲を区切るようにしている。これに対し、第3の実施の形態は、その条件を満たさない音符のなかでフレーズに加えるべき条件を満たしているものを近傍のフレーズに加えるようにしたものである。それにより、他の関連付けるべきフレーズと一部のピッチを変化させたような音符はその変化を無視する形で本来、属すると見なすべきフレーズに帰属させるようにしている。そのようにすることにより、第2の実施の形態と同じく、不要なフレーズ分割をより回避できるようになる。
【0061】
第3の実施の形態における楽曲構造解析装置の構成は、第2の実施の形態と同様に、基本的に第1の実施の形態におけるそれと同じである。動作も大部分は同じか、或いは基本的に同じである。このことから、第1の実施の形態で付した符号をそのまま用いて、第1の実施の形態から異なる部分についてのみ説明する。
【0062】
第3の実施の形態では、図4に示す構造解析処理内でステップSA3として実行されるフレーズ分割処理が第1の実施の形態から異なっている。このことから、始めに、第3の実施の形態におけるフレーズ分割処理について、図12に示すそのフローチャートを参照して詳細に説明する。
【0063】
図12において、ステップSH1〜SH8の処理は図5に示すステップSB1〜SB8のそれと基本的に同じであり、ステップSH10の処理はステップSB9のそれと基本的に同じである。第3の実施の形態では、ステップSH8、SH10間に、ステップSH9として端数処理を実行するようになっている。その端数処理は、ステップSH8のグループ化処理の実行時に、本来、帰属させるべきフレーズから除外された音符をそのフレーズに帰属させるための処理である。
【0064】
図13は、その端数処理のフローチャートである。次に図14を参照して、その端数処理について詳細に説明する。
先ず、ステップSI1では、変数pNotePtrに、楽曲データの先頭に位置する音符データNoteのインデックス値を代入する。次のステップSI2では、変数pNotePtrの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなってステップSI3に移行する。
【0065】
ステップSI3では、Note[pNotePtr].pParentの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSI17で変数pNotePtrにNote[pNotePtr].pNextの値を代入してから上記ステップSI2に戻る。そうでない場合には、判定はYESとなってステップSI4に移行する。
【0066】
ステップSI4では、変数pHeadにNote[pNotePtr].pStartの値を代入する。続くステップSI5では、Note[pNotePtr].pStartの値が変数pHeadの値と等しいか否か判定する。それらの値が等しい場合、判定はYESとなり、ステップSI6で変数pNotePtrにNote[pNotePtr].pNextの値を代入してから上記ステップSI5に戻る。それにより、同じフレーズに属する音符が続く部分のスキップを行う。一方、そうでない場合には、判定はNOとなってステップSI7に移行する。
【0067】
ステップSI7では、変数pTailに変数pNotePtrの値を代入する。次のステップSI8では、変数iCntに0を代入する。その次のステップSI9では、Note[pNotePtr].pStartの値がNULLであり、且つ変数iCntの値が定数iIgnoreNotes未満か否か判定する。定数iIgnoreNotesはフレーズに特別に帰属させる音符数の上限値として定義したものである。このことから、変数pNotePtrの値で指定される音符が何れのフレーズにも属しておらず、且つ変数iCntでカウントした音符数が上限値を下回っている場合、判定はYESとなり、ステップSI10で変数iCntの値をインクリメントし、ステップSI11で変数pNotePtrにNote[pNotePtr].pNextの値を代入してから上記ステップSI9に戻る。それにより、上限値を下回る範囲内で、直前のフレーズの最後に位置する音符以降に続く音符であり、且つフレーズに属さない音符の数のカウントを行う。一方、そうでない場合には、判定はNOとなってステップSI12に移行する。
【0068】
ステップSI12では、変数iCntの値が定数iIgnoreNotes未満か否か判定する。その値が定数iIgnoreNotes以上であった場合、判定はNOとなってステップSI17に移行する。そうでない場合には、判定はYESとなってステップSI13に移行し、変数iCntの値が0より大きいか否か判定する。その値が0より大きい場合、判定はYESとなってステップSI14に移行し、そうでない場合には、判定はNOとなってステップSI17に移行する。
【0069】
ステップSI14では、Note[pTail].pStartとして変数pHeadの値、Note[pTail].iStatusとして2、Note[pTail].pParentとしてNote[pNotePtr−1].pParentの値をそれぞれ設定する。続くステップSI15では、変数pTailにNote[pTail].pNextの値を代入する。その代入後は、ステップSI16で変数iCntの値をデクリメントした後、上記ステップSI13に戻る。それにより、変数iCntでカウントした分の音符を直前にフレーズに帰属させるための設定を行う。
【0070】
このように、本実施の形態では、帰属可能な音符数の上限値として定数iIgnoreNotesを定め、その上限値以上、フレーズに属さない音符が直前のフレーズから続く場合、フレーズへの音符の帰属は行わないようにしている。これは、その上限値以上、続く音符列は別のフレーズとして扱うべき可能性が考えられるためである。その上限値を考慮することにより、フレーズへの音符の帰属をより適切に行えるようにさせている。
【0071】
図14は、フレーズ分割結果の表示例を示す図である。
その表示例は、楽譜上にフレーズ分割結果を表す情報を併せて表示させた場合のものである。図中、「−」が間に挿入された2つの数字は、前側は関連付けられたフレーズに割り当てた番号、後側はフレーズが出現する順番、をそれぞれ表している。それにより、例えば「1−1」「1−2」が付された2小節の長さの部分は共に、関連付けられたフレーズの区間であり、それら2つのフレーズの間に「2−1」「2−2」が付された別と関連付けられたフレーズが演奏されることを表している。この図14に示すような表示例を表示させることにより、楽曲の構造は視覚的にも容易に理解させることができる。
<第4の実施の形態>
上記第1〜第3の実施の形態では、フレーズ間の類似性による関連付けのために音符(音符データNote)単位で対比を行っている。これに対し、第4の実施の形態は、発音タイミングに着目した別データを生成することにより、同一と見なせる一つ以上の音符は1つの別データとして管理し、その別データを対比に利用するようにしたものである。
【0072】
第4の実施の形態における楽曲構造解析装置の構成は、他の実施の形態と同様に、基本的に第1の実施の形態におけるそれと同じである。このことから、第1の実施の形態で付した符号をそのまま用いて説明を行うことにする。
【0073】
第4の実施の形態では、上記他の実施の形態と同じく、楽曲データ、及びフレーズデータを扱っている。その他に、時系列データ、ノートデータ、及びフレーズブロックデータを扱っている。それらは全てRAM102に格納されるデータである。それら各データは以下のようなものである。
【0074】
図15は、第4の実施の形態で扱われる楽曲データの構成を説明する図である。
その楽曲データは、I/F106を介して読み込み、RAM102に格納されるものである。楽曲の演奏内容を音符単位で示す音符データは、図中、括弧を付して表記の「MidiEvent」で表している。その音符データMidiEventは、データiTime、iType、iGate、Pitch、及びpNextの、の各データを備えた構成となっている。データiTypeは、音符データMidiEventの種類を表すものである。楽音の発音を指示する種類(ノートデータ)では0、テンポを指定する種類(テンポデータ)では1となっている。
【0075】
図16は、第4の実施の形態で扱われる時系列データの構成を説明する図である。
その時系列データNoteGroupは、上記別データに相当するものである。対応する1つ以上の音符による発音(演奏)開始ティックを示すデータITime、その終了ティックを示すデータITerm、対応する時系列データがグループ化されているか否かを示すフラグであるデータiGroupFlag、対応するノートデータへのポインタとなるインデックス値であるデータNoteEv、次の時系列データへのポインタとなるインデックス値であるデータNext、前の時系列データへのポインタとなるインデックス値であるデータprev、の各データから構成される。データNoteEvは、対応するノートデータ数分、存在する。
【0076】
図17は、ノートデータの構成を説明する図である。
そのノートデータNoteは、対応する音符データMidiEventへのポインタとなるインデックス値であるデータpEv、そのピッチを示すデータPitch、次のノートデータNoteのインデックス値であるデータnext、前のノートデータNoteのインデックス値であるデータprev、の各データから構成される。
【0077】
図18は、フレーズ管理用データの構成を説明する図である。図18(a)はフレーズデータPhrase、図18(b)はフレーズブロックデータPhBlock、の構成をそれぞれ表している。
【0078】
フレーズデータPhraseは、対応するフレーズの発音(演奏)開始ティックを示すデータITime、その終了ティックを示すデータITerm、フレーズの切れ目(区切り)の種類(分類)を示すデータiType、関連するフレーズデータのなかで先頭のもののインデックス値であるデータpFirst、その最後のもののインデックス値であるデータpEnd、次のフレーズデータPhraseのインデックス値であるデータnext、前のフレーズデータPhraseのインデックス値であるデータprev、の各データから構成される。
【0079】
フレーズブロックデータPhBlockは、関連付けられたフレーズの数であるデータiPhrase、そのなかで先頭に位置するフレーズデータPhraseのインデックス値であるデータpFirst、次のフレーズブロックデータPhBlockのインデックス値であるデータnext、前のフレーズブロックデータPhBlockのインデックス値であるデータprev、の各データから構成される
本実施の形態では、図15に示す楽曲データから図16〜図18に示す各データを生成し、構造解析を行うようになっている。以降は、図19〜図24に示す各種処理のフローチャートを参照して、第4の実施の形態による楽曲構造解析装置の動作について詳細に説明する。
【0080】
図19は、構造解析処理のフローチャートである。始めに図19を参照して、その解析処理について詳細に説明する。その解析処理は、CPU101がROM103に格納されたアプリケーションを実行することで実現される。
【0081】
そのアプリケーションは起動されると、先ず、ステップSJ1で例えばI/F106により記録媒体駆動装置にセットされた記録媒体から楽曲データの読み込みを行い、図16に示すようなデータ構成の時系列データNoteGroupを生成してRAM102に格納する時系列データの生成処理を実行する。その後に移行するステップSJ2では、フレーズ分割処理を実行する。その実行後、一連の処理を終了する。
【0082】
図20は、上記ステップSJ1として実行される時系列データの生成処理のフローチャートである。次に図20を参照して、その生成処理について詳細に説明する。図16に示す時系列データNoteGroup、及び図17に示すノートデータNoteは、その生成処理の実行によって生成される。
【0083】
先ず、ステップSK1では、各種変数を対象にした初期化を行う。変数ngr、ntmp、me、及びphtmpなどにはRAM102の対応する領域のなかで先頭に位置するデータを指定するためのインデックス値が代入される。それに続くステップSK2では、変数meの値で指定される音符データMidiEventのデータpNextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSK3に移行する。
【0084】
ステップSK3では、変数ITProgに、変数meの値で指定される音符データMidiEventのデータITimeの値を代入し、変数nHarmに、ノートデータNoteを格納できる空きエリアのインデックス値を代入する。次のステップSK4では、変数ngrの値で指定される時系列データNoteGroupのデータNoteEvとして変数nHarmの値、そのデータITimeとして変数ITProgの値、そのデータITermとしてMidiEvent[me].IGateの値に変数ITProgの値を加算した値、をそれぞれ設定する。変数nHarmの値で指定されるノートデータNoteでは、データpEvとして変数meの値、データpitchとしてMidiEvent[me].Pitchの値、データprevとして変数nTmpの値、それぞれ設定する。変数nTmpの値で指定されるノートデータNoteのデータnextとしては変数nHarmの値を設定する。それらデータの設定(対応する領域内へのデータの格納)を行い、更に変数nTmpに変数nHarmの値を代入した後はステップSK5に移行する。
【0085】
ステップSK5では、変数ITProgの値からMidiEvent[MidiEvent[me].pNext].ITimeの値を引いた値の絶対値が定数NOTEONOFFSET未満か否か判定する。定数NOTEONOFFSETは和音の構成音間で許容範囲とする発音開始ティックの時間間隔として定めたものである。このことから、その絶対値が示す時間間隔が許容範囲内であった場合、判定はYESとなってステップSK6に移行し、そうでない場合には、判定はNOとなり、ステップSK11で変数meにMidiEvent[me].pNextの値を代入してから上記ステップSK2に戻る。
【0086】
ステップSK6では、変数meHarmに、MidiEvent[me].pNextの値を代入し、変数nHarmに、ノートデータNoteを格納できる空きエリアのインデックス値を代入する。その後に移行するステップSK7では、変数Tに、MidiEvent[meHarm].ITimeの値にMidiEvent[meHarm].IGateの値を加算した値を代入し、その変数Tの値がNoteGroup[ngr].ITermの値より大きければ、そのNoteGroup[ngr].ITermとして変数Tの値を設定する。ステップSK8にはその後に移行する。
【0087】
ステップSK8では、変数nHarmの値で指定されるノートデータNoteにおいて、データpEvとして変数meの値、データpitchとしてMidiEvent[me].Pitchの値、データprevとして変数nTmpの値、をそれぞれ設定する。変数nTmpの値で指定されるノートデータNoteのデータnextとしては変数nHarmの値を設定する。続くステップSK9では、NoteGroup[ngr].NoteEvとして変数meHarmの値を追加し、データNoteEvを対応する音符のピッチ順にソートする。その後は、ステップSK10に移行して、変数meに変数meHarmの値、変数ntmpに変数nHarmの値をそれぞれ代入した後、上記ステップSK5に戻る。それにより、和音の構成音と見なす複数の音符は1つの時系列データNoteGroupにより管理する。
【0088】
図21は、図19に示す構造解析処理内でステップSJ2として実行されるフレーズ分割処理のフローチャートである。次に図21を参照して、その分割処理について詳細に説明する。
【0089】
先ず、ステップSL1では、変数ngRefに時系列データNoteGroupのなかで先頭のものを指定するインデックス値を代入する。続くステップSL2では、NoteGroup[ngRef].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSL3に移行する。
【0090】
ステップSL3では、変数ngSrcに、変数ngRefの値より規定数先の時系列データNoteGroupのデータnextの値を代入する。次のステップSL4では、NoteGroup[ngSrc].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSL9で変数ngRefに、NoteGroup[ngRef].nextの値を代入してから上記ステップSL2に戻る。そうでない場合には、判定はYESとなってステップSL5に移行する。上記規定数とは定数MarkingNotesである。
【0091】
ステップSL5では、変数iMarkCntに0を代入する。続くステップSL6では、先頭位置検索処理を実行する。その後に移行するステップSL7では、変数iMarkCntの値が0でないか否か判定する。その値が0であった場合、判定はNOとなってステップSL9に移行する。そうでない場合には、判定はYESとなり、ステップSL8でグループ化処理を実行した後、上記ステップSL2に戻る。
【0092】
図22は、上記ステップSL6として実行される先頭位置検索処理のフローチャートである。次にその検索処理について、図22に示すそのフローチャートを参照して詳細に説明する。
【0093】
先ず、ステップSM1では、NoteGroup「ngSrc].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSM2に移行する。
【0094】
ステップSM2では、変数jdgに論理値TRUEを代入する。続くステップSM3では、変数iに定数MarkingNotesを代入する。その次のステップSM4では、変数ngReftmpに変数ngRefの値、変数ngSrctmpに変数ngSrcの値をそれぞれ代入する。その代入後に移行するステップSM5では、変数jdgの値がTRUEであり、且つ変数iの値が0より大きいか否か判定する。変数jdgの値がTRUEでないか、或いは変数iの値が0以下であった場合、判定はNOとなってステップSM16に移行する。そうでない場合には、つまり変数jdgの値がTRUEであり、且つ変数iの値が0より大きい場合には、判定はYESとなってステップSM6に移行する。
【0095】
ステップSM6では、NoteGroup「ngSrctmp].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSM15で変数jdgにFALSEを代入し、更にステップSM14で変数iの値をデクリメントした後、上記ステップSM5に戻る。そうでない場合には、判定はYESとなってステップSM7に移行する。
【0096】
ステップSM7では、NoteGroup[ngReftmp].NoteEvの値を変数RefNotetmpに代入し、NoteGroup[ngSrctmp].NoteEvの値を変数SrcNotetmpに代入する。その後に移行するステップSM8では、変数ngReftmpの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「EvNoteGroup[ngReftmp]≠NULL」と表記)、或いは変数ngSrctmpの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「EvNoteGroup[ngSrctmp]≠NULL」と表記)が無いか否か判定する。それらのうちの少なくとも一方の時系列データNoteGroupに他のデータNoteEvが存在しなかった場合、判定はNOとなり、ステップSM11に移行する。そうでない場合には、つまりそれの両方に他のデータNoteEvが存在している場合には、判定はYESとなってステップSM9に移行する。
【0097】
ステップSM9では、変数jdgの値がTRUEであり、且つNote[RefNotetmp].pitchの値がNote[SrcNotetmp].pitchの値と等しければ変数jdgにTRUEを代入する。そうでなければFALSEを代入する。次のステップSM10では、Note[RefNotetmp].nextの値を変数RefNotetmp、Note[SrcNotetmp].nextの値を変数SrcNotetmpにそれぞれ代入する。その代入後は上記ステップSM8に戻る。それにより、データNoteEvが複数、存在している時系列データNoteGroup間では、各データNoteEv毎にその値で指定される音符間のピッチのチェックを行う。
【0098】
一方、ステップSM11では、変数jdgの値がTRUEであり、且つNoteGroup[ngReftmp].ITimeの値からNoteGroup[ngRef].ITimeの値を引いた値に対し、NoteGroup[ngSrctmp].ITimeの値からNoteGroup[ngSrc].ITimeの値を引いた値を減算して得られる値の絶対値が定数StartTickRange未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。次のステップSM12では、変数jdgの値がTRUEであり、且つ変数ngReftmp、ngSrctmpの各値で指定される時系列データNoteGroupで示されるゲートタイムの比を1から引いた値の絶対値が定数GateTimeRatio未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。ステップSM13にはその後に移行して、NoteGroup[ngReftmp].nextの値を変数ngReftmp、NoteGroup[ngSrctmp].nextの値を変数ngSrctmp、にそれぞれ代入する。ステップSM14にはその代入後に移行する。
【0099】
上記ステップSM5の判定がNOとなって移行するステップSM16では、変数jdgの値がTRUEか否か判定する。その値がTRUEであった場合、判定はYESとなってステップSM17に移行する。そうでない場合には、判定NOとなり、ステップSM22で変数ngSrcに、NoteGroup[ngSrc].nextの値を代入した後、上記ステップSM1に戻る。
【0100】
ステップSM17では、変数iMarkCntの値が0か否か判定する。その値が0であった場合、判定はYESとなり、ステップSM18でフレーズデータ登録処理を実行し、次のステップSM19で変数iMarkCntの値をインクリメントし、その次のステップSM20でフレーズデータ登録処理を実行し、更にステップSM21で変数ngSrcに、変数ngSrcの値より規定数先の時系列データNoteGroupのデータne
xtの値を代入する。その後は上記ステップSM1に戻る。
【0101】
上記フレーズデータ登録処理は、ステップSM18では大元のフレーズを対象にして、ステップSM20ではそれと関連付けるフレーズを対象にして行われる。次にその登録処理について、図23に示すそのフローチャートを参照して詳細に説明する。その登録処理を実行することにより、図18(a)に示すフレーズデータPhrase、図18(b)に示すフレーズブロックデータPhBlockが生成される。
【0102】
先ず、ステップSN1では、フレーズデータPhraseのなかで先頭に位置しているもののインデックス値を変数phに代入する。次のステップSN2では、変数phnewに、フレーズデータPhraseが格納されていないエリア(空バッファ)のインデックス値、変数phbnewに、フレーズブロックデータPhBlockが格納されていないエリア(空バッファ)のインデックス値をそれぞれ代入する。その後はステップSN3に移行する。
【0103】
ステップSN3では、変数iMarkCntの値が0か否か判定する。その値が0でなかった場合、判定はNOとなってステップSN9に移行する。そうでない場合には、判定はYESとなってステップSN4に移行する。
【0104】
ステップSN4では、変数nginsに変数ngRefの値、変数ngTermに変数ngReftmpの値、をそれぞれ代入する。続くステップSN5では、Phrase[pbnew].ITimeとしてNoteGroup[ngins].ITimeの値、Phrase[phnew].ITermとしてNoteGroup[ngins].ITermの値、Phrase[phnew].iTypeとして0、Phrase[phnew].pFirstとして変数nginsの値、Phrase[phnew].pEndとして変数ngTermの値、をそれぞれ設定し、変数phbに変数phbnewの値を代入する。ステップSN6には、その後に移行する。
【0105】
ステップSN6では、Phrase[Ph].nextの値がNULLでなく、且つPhrase[Ph].ITimeの値がPhrase[ngins].ITimeの値より大きいか否か判定する。Phrase[Ph].nextの値がNULLか、或いはPhrase[Ph].ITimeの値がPhrase[ngins].ITimeの値以下であった場合、判定はNOとなり、ステップSN7で変数phにPhrase[ph].nextの値を代入した後、そのステップSN6に戻る。そうでない場合には、つまりPhrase[Ph].nextの値がNULLでなく、且つPhrase[Ph].ITimeの値がPhrase[ngins].ITimeの値より大きい場合には、判定はNOとなり、ステップSN8で変数phnewの値で指定されるフレーズデータPhraseを変数phの値で指定されるフレーズデータPhraseより後になるように挿入させる形で格納した後、一連の処理を終了する。
【0106】
上記ステップSN3の判定がNOとなって移行するステップSN9では、PhBlock[phbnew].prevとして変数phbの値、PhBlock[phb].nextとして変数phbnewの値、をそれぞれ設定し、変数phbに変数phbnewの値を代入し、PhBlock[phb].pFirstとして変数phrefの値を設定する。その後は、ステップSN10で変数nginsに変数ngSrc、変数ngTermに変数ngSrctmpの値をそれぞれ代入してからステップSN5に移行する。
【0107】
図24は、図21に示すグループ分割処理内でステップSL8として実行されるグループ化処理のフローチャートである。次にそのグループ化処理について、図24に示すそのフローチャートを参照して詳細に説明する。
【0108】
先ず、ステップSP1では、変数ngReftmpに、Phrase[phRef].pEndの値、変数phSrcに変数phRefの値をそれぞれ代入する。次のステップSP2では、Phrase[phsrc].nextの値がNULLでないか否か判定する。その値がNULLだった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSP3に移行する。
【0109】
ステップSP3では、変数phSrcにPhrase[phRef].nextの値、変数ngSrcにPhrase[phSrc].pFirstの値、変数ngSrctmpにPhrase[phSrc].pEndの値、変数jdgにTRUE、をそれぞれ代入する。その代入後に移行するステップSP4では、変数jdgの値がTRUEであり、且つ、NoteGroup[ngSrctmp].nextの値がNULLでないか否か判定する。変数jdgの値がTRUEでないか、或いはNoteGroup[ngSrctmp].nextの値がNULLであった場合、判定はNOとなってステップSP16に移行し、図9に示すフレーズデータへのグループ登録処理と同様にしてフレーズデータPhraseの更新を行った後、上記ステップSP2に戻る。そうでない場合には、つまり変数jdgの値がTRUEであり、且つ、NoteGroup[ngSrctmp].nextの値がNULLでない場合には、判定はYESとなってステップSP5に移行する。
【0110】
ステップSP5〜SP10では、図22に示すステップSM7〜SM12と同様の処理が行われる。ステップSP10の処理の実行後に移行するステップSP11では、NoteGroup[ngSrctmp].ITimeの値が、Phrase[Phrase[phSrc].next].ITimeの値以上か否か判定する。前者が後者以上であった場合、判定はYESとなり、ステップSP12でPhrase[Phrase[phSrc].next].ITypeとして2を設定した後、ステップSP13に移行する。そうでない場合には、判定はNOとなってそのステップSP13に移行する。
【0111】
ステップSP13では、NoteGroup[ngReftmp].ITimeの値が、Phrase[phSrc].ITimeの値以上か否か判定する。前者が後者以上であった場合、判定はYESとなり、ステップSP14でPhrase[phSrc].ITypeとして2を設定し、変数phSrcに、Phrase[phSrc].nextの値を代入する。そうでない場合には、判定はNOとなってステップSP15に移行する。そのステップSP15では、変数ngReftmpにNoteGroup[ngReftmp].nextの値、変数ngSrctmpにNoteGroup[ngSrctmp].nextの値、をそれぞれ代入する。その代入後は上記ステップSP4に戻る。
<第5の実施の形態>
上記第1〜第4の実施の形態では、類似性に着目してフレーズ分割を行っている。これに対し、第5の実施の形態は、分割時とは異なる視点で、分割したフレーズ間の関連性(類似性)を更に解析するようにしたものである。ここでは、リズム、及び転調の2つに着目して関連性の解析を行うようにしている。そのような解析を行い、その結果を図28に示すようにして提示することにより、楽曲構造をより具体的、且つ容易に理解できるようになる。
【0112】
第5の実施の形態における楽曲構造解析装置の構成は、他の実施の形態と同様に、基本的に第1の実施の形態におけるそれと同じである。このことから、第1の実施の形態で付した符号をそのまま用いて説明を行うことにする。
【0113】
第5の実施の形態では、上記第4の実施の形態で扱うデータの他に、フレーズ関連性データを更に扱っている。その関連性データは、フレーズ間の関連性の解析結果を管理するために用意したものである。
【0114】
図25は、フレーズ管理用データの構成を説明する図である。図25(a)はフレーズブロックデータ、図25(b)はフレーズ関連性データのデータ構成をそれぞれ示している。
【0115】
図25(a)に示すように、第5の実施の形態では、フレーズブロックデータPhBlockは、第4の実施の形態からデータpRelationalが追加されている。そのデータpRelationalは、関連性の解析を行った最初のフレーズデータPhraseのインデックス値である。データpFirstとしては、対応するフレーズデータPhraseのインデックス値を格納するようになっている。
【0116】
フレーズ関連性データは図25(b)に示すように、関連性の解析を行った種類を示すデータiType(リズムは1、転調は2)、解析結果である一致性を示すデータiRatio、対応する、関連性を解析したフレーズのフレーズブロックデータPhBlockのインデックス値であるデータRelationalBlock、次の関連性データPhRelationのインデックス値であるデータnext、前の関連性データPhRelationのインデックス値であるprev、の各データから構成される。
【0117】
上記リズム、及び転調の関連性の解析は、ぞれぞれ図26に示すリズム解析処理、図27に示す転調解析処理を実行することで行われる。それらの解析処理は、例えば図19に示す構造解析処理内でステップSJ2のフレーズ分割処理の実行後に実行するようになっている。本実施の形態では、特に詳細な説明は省略するが、それらのうちの一方のみを選択的に実行するようにしている。以降、それら解析処理について、図26、及び図27を参照して詳細に説明する。
【0118】
始めに、図26を参照してリズム解析処理について詳細に説明する。
先ず、ステップSQ1では、変数の初期化を行う。その初期化により、各データのなかで着目するものを管理するための変数には、そのデータのなかで先頭に位置するもののインデックス値が代入される。その後に移行するステップSQ2では、PhBlock[phbRef].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSQ3に移行する。
【0119】
ステップSQ3では、変数phbSrcに、Phrase[phbRef].nextの値を代入する。その次に移行するステップSQ4では、変数phbSrcの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSQ17でPhBlock[phbRef].nextの値を変数phbRefに代入してから上記ステップSQ2に戻る。そうでない場合には、判定はYESとなってステップSQ5に移行する。
【0120】
ステップSQ5では、Phrase[PhBlock[phbRef].pFirst].pFirstの値(変数phrRefの値で対応するフレーズブロックデータPhBlockが指定されるフレーズの先頭位置に存在する時系列データNoteGroupのインデックス値)を変数ngRefに、Phrase[PhBlock[phbSrc].pFirst].pFirstの値を変数ngSrcに、それぞれ代入する。続くステップSQ6では、変数ngRefの値を変数ngReftmpに、変数ngSrcの値を変数ngSrctmpに、それぞれ代入し、変数iOrgCnt、及びiHitCntにそれぞれ0を代入する。その後は、ステップSQ7で変数iOrgCntの値をインクリメントし、変数jdgにTRUEを代入してからステップSQ8に移行する。
【0121】
ステップSQ8では、変数jdgの値がTRUEであり、且つNoteGroup[ngReftmp].ITIMEの値からNoteGroup[ngRef].ITimeの値を引いた値に対し、NoteGroup[ngSrctmp].ITimeの値からNoteGroup[ngSrc].ITimeの値を引いた値を減算して得られる値の絶対値が定数StartTickRange未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。続くステップSQ9では、変数jdgの値がTRUEであり、且つ変数ngReftmp、ngSrctmpの各値で指定される時系列データNoteGroupで示されるゲートタイムの比を1から引いた値の絶対値が定数GateTimeRatio未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。その後はステップSQ10に移行する。
【0122】
ステップSQ10では、変数jdgの値がTRUEか否か判定する。その値がTRUEであった場合、判定はYESとなり、ステップSQ11で変数iHitCntの値をインクリメントした後、ステップSQ12に移行する。そうでない場合には、判定はNOとなってそのステップSQ12に移行する。
【0123】
ステップSQ12では、Phrase[PhBlock[phbRef].pFirst].pEndの値が変数ngReftmpの値と等しくなく、且つPhrase[PhBlock[phbSrc].pFirst].pEndの値が変数ngSrctmpの値と等しいか否か判定する。それらが共に等しくない場合、判定はYESとなり、ステップSQ13でNoteGroup[ngReftmp].nextの値を変数ngReftmpに、NoteGroup[ngSrctmp].nextの値を変数ngSrctmpに、それぞれ代入した後、上記ステップSQ7に戻る。それにより、フレーズ間での対比を継続して行う。そうでない場合には、つまり少なくとも何れか一方が等しい場合には、判定はNOとなってステップSQ14に移行する。
【0124】
ステップSQ14では、変数phrRに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrR].iTypeとして1を設定し、PhRelation[phrR].RelationalBlockとして変数phbSrcの値を設定し、PhRelation[phrR].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSQ15に移行する。
【0125】
ステップSQ15では、変数phrSに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrS].iTypeとして1を設定し、PhRelation[phrS].RelationalBlockとして変数phbRefの値を設定し、PhRelation[phrS].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSQ16に移行して、PhBlock[phbSrc].nextの値を変数phbSrcに代入する。上記ステップSQ4にはその後に移行する。
【0126】
次に、図27を参照して転調解析処理について詳細に説明する。
図27では、図26に示すリズム解析処理と処理内容が同じ、或いは基本的に同じものには同一の符号を付してある。ここでは、図26から異なる部分に着目して説明することとする。
【0127】
図27の転調解析処理では、ステップSQ10の判定がYESとなるとステップSR1に移行する。そのステップSR1では、NoteGroup[ngRef].NoteEvの値を変数RefNotetmpに代入し、NoteGroup[ngSrc].NoteEvの値を変数SrcNotetmpに代入する。次のステップSR2では、変数ngRefの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「Note[RefNotetmp]≠NULL」と表記)、或いは変数ngSrcの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「Note[SrcNotetmp]≠NULL」と表記)が無いか否か判定する。それらのうちの少なくとも一方の時系列データNoteGroupに他のデータNoteEvが存在しなかった場合、判定はNOとなり、ステップSQ12に移行する。そうでない場合には、つまりそれの両方に他のデータNoteEvが存在している場合には、判定はYESとなってステップSR3に移行する。
【0128】
ステップSR3では、Note[RefNotetmp].pitchの値からNote[SrcNotetmp].pitchの値を引いた値を変数iDifに代入し、配列変数iHitCntの12から変数iDifの値を引いた値で指定される要素iHitCnt[12−iDif]の値をインクリメントする。続くステップSR4では、変数ngRefの値で指定される時系列データNoteGroupに他のデータNoteEvが存在すればNote[RefNotetmp].nextの値を変数RefNotetmp、同様にNote[SrcNotetmp].nextの値を変数SrcNotetmpにそれぞれ代入する。その代入後は上記ステップSR2に戻る。
【0129】
転調解析処理では、ステップSQ12の判定がNOとなるとステップSR5に移行し、配列変数iHitmaxの要素のなかで値が最も大きい要素を指定する値を変数iHitMaxに代入する。次のステップSR6では、変数phrRに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrR].iTypeとして2を設定し、PhRelation[phrR].RelationalBlockとして変数phbSrcの値を設定し、PhRelation[phrR].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSR7に移行する。
【0130】
ステップSR7では、変数phrSに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrS].iTypeとして2を設定し、PhRelation[phrS].RelationalBlockとして変数phbRefの値を設定し、PhRelation[phrS].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSQ16に移行する。
【0131】
なお、本実施の形態では、関連性としてリズム、及び転調に着目した解析を行うようにしているが、それら以外の関連性(類似性)に着目した解析を行うようにしても良い。着目する関連性の異なる複数の解析を一度に行えるようにしても良い。また、特許文献1に記載された技術での構造解析を併せて行い、その結果を反映させた形で構造解析を行うようにしても良い。
【0132】
上述したような楽曲構造解析装置を実現させるようなプログラムは、CD−ROM、DVD、或いは着脱自在なフラッシュメモリ等の記録媒体に記録させて配布しても良い。公衆網等の通信ネットワークを介して、そのプログラムの一部、若しくは全部を配信するようにしても良い。そのようにした場合には、ユーザーはプログラムを取得してデータ処理装置にロードすることにより、その装置に本発明を適用させることができる。このことから、記録媒体は、プログラムを配信する装置がアクセスできるものであっても良い。
【図面の簡単な説明】
【0133】
【図1】第1の実施の形態による楽曲構造解析装置の構成を説明する図である。
【図2】楽曲データの構成を説明する図である。
【図3】フレーズデータの構成を説明する図である。
【図4】構造解析処理のフローチャートである。
【図5】フレーズ分割処理のフローチャートである。
【図6】先端位置検索処理のフローチャートである。
【図7】フレーズデータの登録処理のフローチャートである。
【図8】グループ化処理のフローチャートである。
【図9】フレーズデータへのグループ登録処理のフローチャートである。
【図10】楽曲の分割方法を説明する図である。
【図11】グループ化処理のフローチャートである(第2の実施の形態:抜粋)。
【図12】フレーズ分割処理のフローチャートである(第3の実施の形態)。
【図13】端数処理のフローチャートである。
【図14】楽曲の構造解析結果の表示例を説明する図である(その1)。
【図15】楽曲データの構成を説明する図である(第4の実施の形態)。
【図16】時系列データの構成を説明する図である。
【図17】ノートデータの構成を説明する図である。
【図18】フレーズ管理用データの構成を説明する図である。
【図19】構造解析処理のフローチャートである(第4の実施の形態)。
【図20】時系列データの生成処理のフローチャートである。
【図21】フレーズ分割処理のフローチャートである(第4の実施の形態)。
【図22】先端位置検索処理のフローチャートである(第4の実施の形態)。
【図23】フレーズデータ登録処理のフローチャートである(第4の実施の形態)。
【図24】グループ化処理のフローチャートである(第4の実施の形態)。
【図25】フレーズ管理用データの構成を説明する図である(第5の実施の形態)。
【図26】リズム解析処理のフローチャートである(第5の実施の形態)。
【図27】転調解析処理のフローチャートである(第5の実施の形態)。
【図28】楽曲の構造解析結果の表示例を説明する図である(その2)。
【符号の説明】
【0134】
101 CPU
102 RAM
103 ROM
104 入力装置
105 表示装置
106 インターフェース(I/F)
【技術分野】
【0001】
本発明は、楽曲の演奏内容を音符単位で示す演奏情報を参照して、その楽曲の構造解析を行うための技術に関する。
【背景技術】
【0002】
従来、楽曲の構造解析を行う楽曲構造解析装置としては、例えば特許文献1に記載されたものがある。その特許文献1に記載された楽曲構造解析装置では、音符の発音時間である音符長の変化に着目して、楽曲の分割を行うようにしている。
【0003】
音符長の変化に着目することにより、楽曲全体を部分的な複数の演奏区間に分割することができる。しかし、そのような分割が、確認を望む構造の確認が容易なように常に適切に行えるとは限らない。むしろ、その分割を常に適切に行うためには、確認したい構造に着目して行うのが望ましいと言える。その構造として、類似する演奏内容の演奏が異なる複数の部分で行われる繰り返し構造も重要なものの一つであると考えられる。
【特許文献1】特開2002−132255号公報
【発明の開示】
【発明が解決しようとする課題】
【0004】
本発明の課題は、繰り返し構造に着目した楽曲の分割を常に適切に行うための技術を提供することにある。
【課題を解決するための手段】
【0005】
本発明の楽曲構造解析装置は、楽曲の構造の解析を行うことを前提とし、楽曲の演奏内容を音符単位で示す演奏情報を取得する演奏情報取得手段と、演奏情報取得手段が取得した演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、楽曲から演奏内容が類似する複数の演奏区間を抽出する構造解析手段と、を具備する。
【0006】
なお、上記構造解析手段は、音符による発音時間の相違を考慮して解析を行う、ことが望ましい。また、演奏区間として抽出されない部分に存在する音符のなかで所定の条件を満たす音符は該演奏区間に含める、ことが望ましい。
【0007】
本発明のプログラムは、上記楽曲構造解析装置が具備する手段を実現させるための機能を搭載している。
【発明の効果】
【0008】
本発明は、楽曲の演奏内容を音符単位で示す演奏情報を取得し、その演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、楽曲から演奏内容が類似する複数の演奏区間を抽出する。そのように演奏内容が類似性(関連性)を有する演奏区間を抽出することにより、楽曲の繰り返し構造が容易に確認できるようになる。このため、その繰り返し構造を通して、フレーズ構造の確認も容易に行えるようになる。
【発明を実施するための最良の形態】
【0009】
以下、本発明の実施の形態について、図面を参照しながら詳細に説明する。
<第1の実施の形態>
図1は、第1の実施の形態による楽曲構造解析装置の構成を説明する図である。
【0010】
その楽曲構造解析装置は、図1に示すように、装置全体の制御を行うCPU101と、そのCPU101がワークに用いるRAM102と、CPU101が実行するプログラムや各種制御用データを格納したROM103と、例えば各種キー等の操作子を有するキーボードやポインティングデバイス等である入力装置104と、例えば液晶表示装置である表示装置105と、外部装置との間でデータの入出力を行うインターフェース(I/F)106と、を備えて構成されている。
【0011】
上記I/F106は、例えば光ディスク装置や光磁気ディスク装置などの記録媒体駆動装置との間でデータの入出力を行うものか、或いは通信ネットワークを介した通信を行う通信制御装置である。ここでは、前者であるとの前提で説明を行うことにする。
【0012】
上述したような構成の楽曲構造解析装置は、例えばパーソナルコンピュータ(PC)、或いはPDAといったデータ処理装置である。その解析装置は、後述するような動作を行わせるプログラム(アプリケーション・プログラム。以降「アプリケーション」と略記)をCPU101に実行させることで実現される。ここでは便宜的に、そのアプリケーションはROM103に格納されていることとする。
【0013】
そのアプリケーションは、楽曲の演奏内容を示す楽曲データを参照し、その楽曲データが示す部分的な演奏内容の類似性に着目した構造解析を行い、演奏内容が類似すると見なす演奏区間を楽曲から抽出する。それにより、他に類似するものが存在する演奏区間とそうでない部分(演奏区間)とに大別する。
【0014】
そのように演奏内容が類似する演奏区間を抽出することにより、楽曲の繰り返し構造が容易に確認できるようになる。その繰り返し構造を通して、フレーズ構造の確認も容易に行えるようになる。演奏を行っていく際の指の運びである運指を示す運指情報の生成では、例えば演奏内容が同一の演奏区間ではその前後の部分に係わらずに同一の運指情報の生成を行えるようになる。それにより、演奏内容が同じでありながら前、或いは後の部分の違いによって運指が異なることに違和感を覚えるような人に対しては、違和感を与えないような運指情報を生成できることとなる。演奏区間の抽出は、その演奏区間に存在する音符をグループ化することに相当する。その演奏区間については以降「フレーズ」と呼ぶことにする。
【0015】
図2は、上記楽曲データの構成を説明する図である。
その楽曲データは、I/F106を介して読み込まれ、RAM102に格納される。楽曲の演奏内容を音符単位で示すデータ(以降「音符データ」と呼ぶ)の集合体として構成されている。図中に括弧を付して表記の「Note」はその音符データを表している。括弧内の数値は、音符データを指定するインデックス(値)である。以降、インデックスが判明している音符データには「Note」、及びそれに続けて括弧内にインデックスを示す数値、或いは変数のシンボルを表記したものを付して例えば「音符データNote[0]」といったように記載し、そのインデックスが判明していない音符データには単に「Note」を付して記載することとする。これは他でも同様である。
【0016】
その音符データNoteは、「iTime」と表記の発音開始ティック(時刻)、「iGate」と表記のゲートタイム(発音継続時間)、「Pitch」と表記のピッチ(ノート番号)、「pParent」と表記の当該音符データNoteが属するグループの先頭に位置する音符データNoteのインデックス、「pStart」と表記のそのグループと演奏内容が類似しているとして関連付けられた他のグループの先頭に位置する音符データNoteのインデックス、「iStatus」と表記のグループ化された状態を示すフラグ、「pNext」と表記の次に処理対象となる音符データNoteのインデックス、及び「pRev」と表記の前に処理対象となる音符データNoteのインデックス、の各データを備えた構成となっている。それらのなかで、データiTime、iGate、Pitch、pNext、及びpRevはI/F106を介して読み込んだ楽曲データを構成するデータか、或いはそれから生成されるデータである。
【0017】
グループ間の対応関係を管理するために、本実施の形態では、図3に示すフレーズデータを生成しRAM102に確保した領域に保存するようにしている。図中に括弧を付して表記の「Phrase」はそのフレーズデータを表している。括弧内の数値は、フレーズデータを指定するインデックス(値)である。以降、同様にインデックスが判明しているフレーズデータには「Phrase」、及びそれに続けて括弧内にインデックスを示す数値、或いは変数のシンボルを表記したものを付して記載することとする。
【0018】
そのフレーズデータPhraseは、「pOrgParent」と表記の大元となるグレープの先頭に位置する音符データNoteのインデックス、「pStart」と表記の対応するグループの先頭に位置する音符データNoteのインデックス、「iNoteCnt」と表記のグループに属する音符データNote数、「ITotalTick」と表記のグループの総演奏時間(合計時間)、「pNextGroup」と表記の次のグループデータPhraseのインデックス、の各データを備えた構成となっている。
【0019】
以降は、図4〜図9に示す各種処理のフローチャート、及び図10に示す説明図を参照しつつ、楽曲構造解析装置の動作について詳細に説明する。
図4は、構造解析処理のフローチャートである。始めに図4を参照して、その解析処理について詳細に説明する。その解析処理は、CPU101がROM103に格納されたアプリケーションを実行することで実現される。
【0020】
そのアプリケーションは起動されると、先ず、ステップSA1で各種データ(変数を含む)の初期化を行う。続くステップSA2では、例えばI/F106により記録媒体駆動装置にセットされた記録媒体から楽曲データの読み込みを行い、図2に示すようなデータ構成でRAM102に格納する。その後に移行するステップSA3では、楽曲をフレーズ(類似するものが他に存在するフレーズ)に分割するフレーズ分割処理を実行する。一連の処理はその後に終了する。
【0021】
図5は、上記ステップSA3として実行されるフレーズ分割処理のフローチャートである。次にその分割処理について、図5に示すそのフローチャートを参照して詳細に説明する。
【0022】
先ず、ステップSB1では、楽曲データを構成する各音符データNoteのデータpParent、pStartにNULL(値としては0である)を代入する。次のステップSB2では、変数pRefNoteに、楽曲データの先頭に位置する音符データNoteのインデックスを代入し、変数pRefLastに、その音符データNoteから定数MarkingNotesだけ先の音符データNoteのインデックス値を代入する。ステップSB3にはその後に移行する。定数MarkingNotesは、グループと見なさない最小の音符数として定義したものである。
【0023】
ステップSB3では、変数pRefLastの値で指定される音符データNote(図中「Note[pRefLast]」と表記。以降、その表記法も用いることにする。これは他でも同様である)のデータpNextの値がNULLでないか否か判定する。その値がNULLであった場合、つまりその音符データNoteが最後のものであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSB4に移行する。
【0024】
ステップSB4では、変数pRefNoteの値で指定される音符データNoteのデータpStartの値がNULLか否か判定する。その音符データNoteがグループ化されていない場合、その値はNULLであることから、判定はYESとなり、ステップSB5で変数iMarkCntに0を代入し、更にステップSB6で関連付けるグループの先頭位置を検索するための先頭位置検索処理を実行してからステップSB7に移行する。そうでない場合には、判定はNOとなってステップSB9に移行する。
【0025】
上記変数iMarkCntは、検索により抽出した先頭位置の数を計数するためのものである。ステップSB7では、その値が0でないか否か判定する。その先頭位置が抽出された場合、その値は0より大きい値に更新されることから、判定はYESとなり、ステップSB8でグループ化処理を実行し、次のステップSB9で変数pRefNoteに、変数pRefNoteの値で指定される音符データNoteのデータpNextの値、変数pRefNoteに、その音符データNoteから定数MarkingNotesだけ先の音符データNoteのデータpNextの値を代入してから上記ステップSB3に戻る。そうでない場合には、判定はNOとなり、次にそのステップSB9に移行する。
【0026】
このようにして、フレーズ分割処理では、変数pRefNoteの値を順次、更新しながら、その値で指定される音符(音符データNote)が先頭位置に存在するグループ(フレーズ)を大元のグループとして、そのグループと関連付けられる他のグループを探すようになっている。その他のグループが探し出せた場合、大元のグループ、及びその他のグループの登録を行っている。
【0027】
次に、上記ステップSB6として実行される先頭位置検索処理について、図6に示すそのフローチャートを参照して詳細に説明する。
先ず、ステップSC1では、変数pLookupNoteにNote[pRefLast].pNext(変数pRefLastの値で指定される音符データNoteのデータpNext)の値を代入する。次のステップSC2では、変数pLookupNoteの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLでない場合、判定はYESとなってステップSC5に移行する。そうでない場合には、判定はNOとなってステップSC3に移行する。
【0028】
ステップSC3では、変数iMarkCntの値が0より大きいか否か判定する。その値が0より大きい場合、判定はYESとなってステップSC4に移行し、フレーズデータPhraseの登録を行うためのフレーズデータの登録処理を実行した後、一連の処理を終了する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
【0029】
ステップSC5では、変数jdgに論理値TRUEを代入する。続くステップSC6では、変数iに定数MarkingNotesを代入する。その次のステップSC7では、変数pNotetmpに変数pLookupNoteの値、変数pReftmpに変数pRefNoteの値をそれぞれ代入する。その後に移行するステップSC8では、変数jdgの値がTRUEであり、且つ変数iの値が0より大きいか否か判定する。変数jdgの値がTRUEであり、且つ変数iの値が0より大きい場合、判定はYESとなってステップSC9に移行する。そうでない場合には、つまり変数jdgの値がFALSEか、或いは変数iの値が0以下であった場合には、判定はNOとなってステップSC16に移行する。
【0030】
ステップSC9では、変数pRefNoteの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLでない場合、つまりそれ以降の音符データNoteが存在しない場合、判定はYESとなってステップSC10に移行する。そうでない場合には、判定はNOとなり、ステップSC15で変数jdgにFALSEを代入し、更にステップSC14で変数iの値をデクリメント(図中「−−」と表記)してから上記ステップSC8に戻る。
【0031】
ステップSC10では、変数jdgの値がTRUEであり、且つNote[pReftmp].Pitchの値とNote[pNotetmp].Pitchの値が等しければ(変数pReftmp、pNotetmpの各値で指定される音符のピッチが等しければ)TRUEを代入する。そうでなければFALSEを代入する。続くステップSC11では、変数jdgの値がTRUEであり、且つNote[pNotetmp].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pReftmp].ITimeの値からNote[pRefNote].ITimeの値を引いて得られる値が定数StartTickRange未満であれば(それら発音開始ティックの時間間隔の差が定数StartTickRangeとして用意した閾値未満であれば)TRUEを代入する。そうでなければFALSEを代入する。その次のステップSC12では、変数jdgの値がTRUEであり、且つNote[pReftmp].IGateの値をNote[pNotetmp].IGateの値で割った値を1から引いた値の絶対値が定数IGateTimeRatio未満であれば(それらのゲートタイム比が許容範囲内であれば)TRUEを代入する。そうでなければFALSEを代入する。その後は、ステップSC13において、変数pNotetmpにNote[pNotetmp].pNextの値、変数pReftmpにNote[pReftmp].pNextの値をそれぞれ代入してからステップSC14に移行する。
【0032】
このようにして、本実施の形態では、音符のピッチが等しい、発音開始ティック間の時間間隔の差が許容範囲内、ゲートタイム比が許容範囲内、という条件を全て満たしていなければ変数jdgにはFALSEを代入するようにしている。それにより、抽出する先頭位置としては、それらの条件を音符毎に全て満足する音符数が定数MarkingNotes以上となっている音符群を対象にしている。その対象となる条件については便宜的に「フレーズ成立条件」と呼び、音符毎に満足すべき全ての条件については「音符成立条件」と呼ぶことにする。フレーズ成立条件は、定数MarkingNotes以上、連続して音符成立条件が満たされた場合に満たすことになる。
【0033】
上記ステップSC8の判定がNOとなって移行するステップSC16では、変数jdgの値がTRUEか否か判定する。その値がTRUEであった場合、つまりフレーズ成立条件を満たす、抽出すべき先頭位置が抽出できた場合、判定はYESとなり、ステップSC18でNote[pLookupNote].pParentに変数pRefNoteの値を代入し、ステップSC19で変数iMarkCntの値をインクリメント(図中「++」と表記)し、更にステップSC20で変数pLookupNoteにNote[pNotetmp].pNextの値を代入してから上記ステップSC2に戻る。そうでない場合には、判定はNOとなり、ステップSC17で変数pLookupNoteにNote[pLookupNote].pNextの値を代入してから上記ステップSC2に戻る。
【0034】
このようにして、変数pRefNoteの値で指定される音符(音符データNote)を大元のフレーズの先頭位置と想定し、そのフレーズとフレーズ成立条件を満たす各フレーズの先頭位置の音符データNoteにデータpParentとして変数pRefNoteの値をそれぞれ設定するようにしている。その設定により、先頭位置の音符をマーキングしている。
【0035】
図7は、上記ステップSC4として実行されるフレーズデータの登録処理のフローチャートである。次に図7を参照して、その登録処理について詳細に説明する。
先ず、ステップSD1では、変数iPに0を代入する。続くステップSD2では、その変数iPの値で指定されるフレーズデータPhraseのデータpOrgParentの値がNULLか否か判定する。その値がNULLでない場合、判定はNOとなり、ステップSD3で変数iPの値をインクリメントしてから、再度ステップSD2の判定処理を行う。そうでない場合には、判定はYESとなってステップSD4に移行し、Phrase[iP].pOrgParent、及びPhrase[iP].pStartとして変数pRefNoteの値、Phrase[iP].iNoteCntとして定数MarkingNotes、Phrase[iP].ITotalTickとして、Note[pRefLast].ITimeの値にNote[pRefLast].IGateの値を加算した値からNote[pRefNote].ITimeの値を引いて得られる値(定数MarkingNotes分の総演奏時間)をそれぞれ代入する。一連の処理はその後に終了する。
【0036】
図8は、図5に示すフレーズ分割処理内でステップSB8として実行されるグループ化処理のフローチャートである。次にそのグループ化処理について、図8を参照して詳細に説明する。
【0037】
先ず、ステップSF1では、変数pLookupNoteにNote[pRefLast].pNextの値を代入する。次のステップSF2では、変数pLookupNoteの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLでない場合、判定はYESとなってステップSF3に移行する。そうでない場合には、判定はNOとなり、ここで一連の処理を終了する。
【0038】
ステップSF3では、変数pLookupNoteの値で指定される音符データNoteのデータpParentの値が変数pRefNoteの値と等しいか否か判定する。それらの値が等しくない場合、判定はNOとなり、ステップSF4で変数pLookupNoteにNote[pRefLast].pNextの値を代入した後、上記ステップSF2に戻る。そうでない場合には、判定はYESとなってステップSF5に移行する。それにより、関連付けられるフレーズの先頭位置としてマーキングされた音符の抽出を行う。
【0039】
ステップSF5では、変数pNotetmpに変数pLookupNoteの値、変数pReftmpに変数pRefNoteの値をそれぞれ代入する。次のステップSF6では、変数jdgにTRUEを代入する。その後は、ステップSF7で変数iに1を代入してからステップSF8に移行する。
【0040】
ステップSF8では、変数jdgの値がTRUEであり、且つ変数pNotetmpの値で指定される音符データNoteのデータpNextの値がNULLか否か判定する。変数jdgの値がTRUEでないか、或いはそのデータpNextの値がNULLであった場合、判定はNOとなってステップSF14に移行する。そうでない場合には、判定はYESとなってステップSF9に移行する。
【0041】
ステップSF9〜SF12では、図6に示すステップSC10〜SC13と同様の処理が行われる。ステップSF12の処理の実行後は、ステップSF13に移行して、変数iの値をインクリメントしてから上記ステップSF8に戻る。それにより、連続して音符成立条件を満たす音符数のカウントを継続させる。
【0042】
上記ステップSF8の判定がNOとなって移行するステップSF14では、変数iの値が定数MarkingNotesより大きいか否か判定する。その値が定数MarkingNotes以下であった場合、判定はNOとなり、ステップSF15でNote[pLookupNote].pParentとしてNULLを設定し、ステップSF16で変数pLookupNoteにNote[pLookupNote].pNextの値を代入してから上記ステップSF2に戻る。一方、そうでない場合には、つまり変数iの値が定数MarkingNotesより大きい場合には、判定はYESとなってステップSF17に移行する。
【0043】
ステップSF17では、フレーズデータ間の関連付けを行いつつ、フレーズデータの登録を行うフレーズデータへのグループ登録処理を実行する。続くステップSF18では、変数pNoteRsltに変数pLookupNoteの値を代入する。その後はステップSF19に移行する。
【0044】
ステップSF19では、変数pNotetmpの値が変数pNoteRsltの値と等しくないか否か判定する。それらの値が等しい場合、判定はNOとなってステップSF16に移行する。そうでない場合には、判定はYESとなり、ステップSF20でNote[pNoteRslt].pStartに変数pLookupNoteの値、Note[pNoteRslt].pParentに変数pRefNoteの値をそれぞれ代入し、次のステップSF21で変数pNoteRsltにNote[pNoteRslt].pNextの値を代入してから上記ステップSF19に戻る。それにより、大元のフレーズと関連付けられたフレーズを構成する各音符データNoteのデータpStartとして、その大元のフレーズの先頭位置の音符データNoteを指定する値が設定される。データpParentとしては、属するフレーズの先頭位置の音符データNoteを指定する値が設定される。
【0045】
図10は、楽曲の分割方法を説明する図である。
楽曲の分割、つまり関連付けるべきフレーズの抽出は、図10に示すように、始めに先頭位置検索により、先頭部分の音符が全て音符成立条件を満たすフレーズの先頭位置の音符に対してマーキングを行い、その後、音符成立条件を満たさなくなるまでの範囲をフレーズの範囲として再度、特定(検索)することで行われる。先頭位置の音符に対するマーキングは、図6に示す先頭位置検索処理の実行により行われ、再度の検索はグループ化処理を実行することで行われる。
【0046】
図9は、上記ステップSF17として実行されるフレーズデータへのグループ登録処理のフローチャートである。最後に図9を参照して、その登録処理について詳細に説明する。
【0047】
先ず、ステップSE1では、変数iPに0を代入する。続くステップSE2では、その変数iPの値で指定されるフレーズデータPhraseのデータpOrgParentの値が変数pRefNoteの値と等しいか否か判定する。それらの値が一致する場合、判定はYESとなってステップSE6に移行する。そうでない場合には、判定はNOとなってステップSE3に移行する。
【0048】
ステップSE3では、変数iPの値で指定されるフレーズデータPhraseのデータpOrgParentの値がNULLか否か判定する。その値がNULLでない場合、判定はNOとなり、ステップSE4で変数iPの値をインクリメントしてから上記ステップSE2に戻る。そうでない場合には、判定はYESとなってステップSE5に移行し、Phrase[iP].pOrgParentとして変数pRefNoteの値、Phrase[iP].pStartとして変数pLookupNoteの値、Phrase[iP].iNoteCntとして変数iの値、Phrase[iP].ITotalTickとして、Note[pNotetmp].ITimeの値にNote[pNotetmp].IGateの値を加算した値からNote[pLookupNote].ITimeの値を引いて得られる値(フレーズ全体での総演奏時間)をそれぞれ代入する。一連の処理はその後に終了する。
【0049】
上記ステップSE2の判定がYESとなって移行するステップSE6では、Phrase[iP].iNoteCntの値が変数iの値未満か否か判定する。変数iPの値で指定されるフレーズの音符数が変数iの値以上であった場合、判定はNOとなってステップSE3に移行する。そうでない場合には、判定はYESとなってステップSE7に移行し、Phrase[iP].iNoteCntとして変数iの値、Phrase[iP].ITotalTickとして、Note[pReftmp].ITimeの値にNote[pReftmp].IGateの値を加算した値からNote[pRefNote].ITimeの値を引いて得られる値をそれぞれ代入する。また、変数pRefNoteの値で指定される音符データNoteから変数iの値分の音符データNoteに対し、データpParent、pStartとして変数pRefNoteの値をそれぞれ設定する。一連の処理はその後に終了する。
【0050】
このようにして、本実施の形態では、関連付けたフレーズ間で総演奏時間が異なる場合、フレーズのなかで最も長い総演奏時間のものを各フレーズの総演奏時間とさせている。それにより、基本的には同じと見なすべきフレーズのなかで最後を他と変化させたようなものはその変化させた部分の存在を過大に評価しないようにさせている。
<第2の実施の形態>
上記第1の実施の形態では、音符を一対一に対応付けてフレーズ間の対比を行っている。これに対し、第2の実施の形態は、音符長を考慮してフレーズ間の対比を行うようにしたものである。
【0051】
楽曲では、実質的には同じフレーズであってもその一部を変更させることがある。具体的には、発音される楽音を複数の楽音に置き換えたり(分割)、或いはその逆に、複数の楽音をまとめて1つの楽音とさせたり(結合)することがある。このようなことから、第2の実施の形態では、そのような分割や結合にも適切に対応できるように、音符長を考慮したフレーズ間の対比を行うようにしている。
【0052】
第2の実施の形態における楽曲構造解析装置の構成は、基本的に第1の実施の形態におけるそれと同じである。動作も大部分は同じか、或いは基本的に同じである。このことから、第1の実施の形態で付した符号をそのまま用いて、第1の実施の形態から異なる部分についてのみ説明する。
【0053】
第2の実施の形態では、図8に示すグループ化処理において、ステップSF7〜SF10間が第1の実施の形態から異なっている。このことから、その異なる部分について、図11に示すフローチャートを参照して詳細に説明する。
【0054】
第2の実施の形態では、ステップSF7から移行するステップSF8の判定がYESとなると、次にステップSG1に移行して、変数TickDifに、Note[pNotetmp].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pReftmp].ITimeの値からNote[pRefNote].ITimeの値を引いた値を減算して得られる値(フレーズ間における、異なる音符間の発音開始ティックの時間間隔の差)を代入する。その後に移行するステップSG2では、変数TickDifの値が定数StartTickRangeより大きいか否か判定する。その値が定数StartTickRangeより大きい場合、つまり関連付けされるフレーズのほうが大元のフレーズより時間間隔が無視できない差で長い場合、判定はYESとなってステップSG4に移行し、そうでない場合には、判定はNOとなってステップSG3に移行する。
【0055】
ステップSG3では、変数TickDifの値が負の値の定数StartTickRangeより小さいか否か判定する。その値が負の値の定数StartTickRangeより小さい場合、つまり関連付けされるフレーズのほうが大元のフレーズより時間間隔が無視できない差で短い場合、判定はYESとなってステップSG10に移行し、そうでない場合には、判定はNOとなってステップSF9に移行する。
【0056】
上記ステップSG4では、変数pNoteSkipに、Note[pReftmp].pNextの値を代入する。次のステップSG5では、Note[pNotetmp].ITimeの値が、Note[pNoteSkip].ITimeの値より大きいか否か判定する。前者が後者以下であった場合、判定はNOとなってステップSG3に移行する。そうでない場合には、判定はYESとなってステップSG6に移行する。
【0057】
ステップSG6では、変数TickDif2に、Note[pNotetmp].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pNoteSkip].ITimeの値からNote[pRefNote].ITimeの値を引いた値を減算して得られる値を代入する。その後に移行するステップSG7では、変数TickDifの値の絶対値が定数StartTickRangeより小さいか否か判定する。その絶対値が定数StartTickRangeより小さい場合、つまり2つのフレーズ間における時間間隔の差が許容範囲内であった場合、判定はYESとなり、ステップSG9で変数nReftmpに変数pNoteSkipの値を代入した後、ステップSG3に移行する。そうでない場合には、判定はNOとなってステップSG8に移行し、変数pNoteSkipにNote[pNoteSkip].pNextの値を代入する。その後はステップSG5に戻る。それにより、大元のフレーズ側で着目する音符を先に進めることで時間的な調整が可能か否かの確認を再度、行う。そのような確認により、例えば大元のフレーズでは2個の八分音符が存在する演奏区間に、関連付けられるフレーズでは1個の四分音符が存在しているのであれば、2個の八部音符を1個の四分音符と対応付けて両者の演奏時間は対比されることとなる。
【0058】
ステップSG3の判定がYESとなって移行するステップSG10では、変数iSkipに1を代入する。続くステップSG11では、変数pNoteSkipにNote[pNotetmp].pNextの値を代入する。その後はステップSG12に移行して、Note[pNoteSkip].ITimeの値が、Note[pNoteSkip].ITimeの値より大きいか否か判定する。前者が後者以下であった場合、判定はNOとなってステップSG9に移行する。そうでない場合には、判定はYESとなってステップSG13に移行する。
【0059】
ステップSG13では、変数TickDif2に、Note[pNoteSkip].ITimeの値からNote[pLookupNote].ITimeの値を引いた値に対し、Note[pReftmp].ITimeの値からNote[pRefNote].ITimeの値を引いた値を減算して得られる値を代入する。その後に移行するステップSG14では、変数TickDifの値の絶対値が定数StartTickRangeより小さいか否か判定する。その絶対値が定数StartTickRangeより小さい場合、つまり2つのフレーズ間における時間間隔の差が許容範囲内であった場合、判定はYESとなってステップSG17に移行する。そうでない場合には、判定はNOとなり、ステップSG15で変数iSkipの値をインクリメントし、ステップSG16で変数pNoteSkipにNote[pNoteSkip].pNextの値を代入する。その後はステップSG12に戻る。それにより、大元のフレーズと関連付けられるフレーズ側で着目する音符を先に進めることで時間的な調整が可能か否かの確認を再度、行う。
【0060】
ステップSG17では、変数iSkipの値が0より大きいか否か判定する。その値が0より大きい場合、判定はYESとなり、ステップSG18でNote[pNotetmp].iStatusとして1を設定し、ステップSG19で変数pNotetmpにNote[pNotetmp].pNextの値を代入し、更にステップSG20で変数iSkipの値をデクリメントしてからステップSG17に戻る。それにより、大元のフレーズ側で該当する音符が存在しない音符の全てにデータiStatusとして1を設定する。
<第3の実施の形態>
上記第1、及び第2の実施の形態では、基本的に、音符成立条件が満足しなくなったところでフレーズの範囲を区切るようにしている。これに対し、第3の実施の形態は、その条件を満たさない音符のなかでフレーズに加えるべき条件を満たしているものを近傍のフレーズに加えるようにしたものである。それにより、他の関連付けるべきフレーズと一部のピッチを変化させたような音符はその変化を無視する形で本来、属すると見なすべきフレーズに帰属させるようにしている。そのようにすることにより、第2の実施の形態と同じく、不要なフレーズ分割をより回避できるようになる。
【0061】
第3の実施の形態における楽曲構造解析装置の構成は、第2の実施の形態と同様に、基本的に第1の実施の形態におけるそれと同じである。動作も大部分は同じか、或いは基本的に同じである。このことから、第1の実施の形態で付した符号をそのまま用いて、第1の実施の形態から異なる部分についてのみ説明する。
【0062】
第3の実施の形態では、図4に示す構造解析処理内でステップSA3として実行されるフレーズ分割処理が第1の実施の形態から異なっている。このことから、始めに、第3の実施の形態におけるフレーズ分割処理について、図12に示すそのフローチャートを参照して詳細に説明する。
【0063】
図12において、ステップSH1〜SH8の処理は図5に示すステップSB1〜SB8のそれと基本的に同じであり、ステップSH10の処理はステップSB9のそれと基本的に同じである。第3の実施の形態では、ステップSH8、SH10間に、ステップSH9として端数処理を実行するようになっている。その端数処理は、ステップSH8のグループ化処理の実行時に、本来、帰属させるべきフレーズから除外された音符をそのフレーズに帰属させるための処理である。
【0064】
図13は、その端数処理のフローチャートである。次に図14を参照して、その端数処理について詳細に説明する。
先ず、ステップSI1では、変数pNotePtrに、楽曲データの先頭に位置する音符データNoteのインデックス値を代入する。次のステップSI2では、変数pNotePtrの値で指定される音符データNoteのデータpNextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はNOとなってステップSI3に移行する。
【0065】
ステップSI3では、Note[pNotePtr].pParentの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSI17で変数pNotePtrにNote[pNotePtr].pNextの値を代入してから上記ステップSI2に戻る。そうでない場合には、判定はYESとなってステップSI4に移行する。
【0066】
ステップSI4では、変数pHeadにNote[pNotePtr].pStartの値を代入する。続くステップSI5では、Note[pNotePtr].pStartの値が変数pHeadの値と等しいか否か判定する。それらの値が等しい場合、判定はYESとなり、ステップSI6で変数pNotePtrにNote[pNotePtr].pNextの値を代入してから上記ステップSI5に戻る。それにより、同じフレーズに属する音符が続く部分のスキップを行う。一方、そうでない場合には、判定はNOとなってステップSI7に移行する。
【0067】
ステップSI7では、変数pTailに変数pNotePtrの値を代入する。次のステップSI8では、変数iCntに0を代入する。その次のステップSI9では、Note[pNotePtr].pStartの値がNULLであり、且つ変数iCntの値が定数iIgnoreNotes未満か否か判定する。定数iIgnoreNotesはフレーズに特別に帰属させる音符数の上限値として定義したものである。このことから、変数pNotePtrの値で指定される音符が何れのフレーズにも属しておらず、且つ変数iCntでカウントした音符数が上限値を下回っている場合、判定はYESとなり、ステップSI10で変数iCntの値をインクリメントし、ステップSI11で変数pNotePtrにNote[pNotePtr].pNextの値を代入してから上記ステップSI9に戻る。それにより、上限値を下回る範囲内で、直前のフレーズの最後に位置する音符以降に続く音符であり、且つフレーズに属さない音符の数のカウントを行う。一方、そうでない場合には、判定はNOとなってステップSI12に移行する。
【0068】
ステップSI12では、変数iCntの値が定数iIgnoreNotes未満か否か判定する。その値が定数iIgnoreNotes以上であった場合、判定はNOとなってステップSI17に移行する。そうでない場合には、判定はYESとなってステップSI13に移行し、変数iCntの値が0より大きいか否か判定する。その値が0より大きい場合、判定はYESとなってステップSI14に移行し、そうでない場合には、判定はNOとなってステップSI17に移行する。
【0069】
ステップSI14では、Note[pTail].pStartとして変数pHeadの値、Note[pTail].iStatusとして2、Note[pTail].pParentとしてNote[pNotePtr−1].pParentの値をそれぞれ設定する。続くステップSI15では、変数pTailにNote[pTail].pNextの値を代入する。その代入後は、ステップSI16で変数iCntの値をデクリメントした後、上記ステップSI13に戻る。それにより、変数iCntでカウントした分の音符を直前にフレーズに帰属させるための設定を行う。
【0070】
このように、本実施の形態では、帰属可能な音符数の上限値として定数iIgnoreNotesを定め、その上限値以上、フレーズに属さない音符が直前のフレーズから続く場合、フレーズへの音符の帰属は行わないようにしている。これは、その上限値以上、続く音符列は別のフレーズとして扱うべき可能性が考えられるためである。その上限値を考慮することにより、フレーズへの音符の帰属をより適切に行えるようにさせている。
【0071】
図14は、フレーズ分割結果の表示例を示す図である。
その表示例は、楽譜上にフレーズ分割結果を表す情報を併せて表示させた場合のものである。図中、「−」が間に挿入された2つの数字は、前側は関連付けられたフレーズに割り当てた番号、後側はフレーズが出現する順番、をそれぞれ表している。それにより、例えば「1−1」「1−2」が付された2小節の長さの部分は共に、関連付けられたフレーズの区間であり、それら2つのフレーズの間に「2−1」「2−2」が付された別と関連付けられたフレーズが演奏されることを表している。この図14に示すような表示例を表示させることにより、楽曲の構造は視覚的にも容易に理解させることができる。
<第4の実施の形態>
上記第1〜第3の実施の形態では、フレーズ間の類似性による関連付けのために音符(音符データNote)単位で対比を行っている。これに対し、第4の実施の形態は、発音タイミングに着目した別データを生成することにより、同一と見なせる一つ以上の音符は1つの別データとして管理し、その別データを対比に利用するようにしたものである。
【0072】
第4の実施の形態における楽曲構造解析装置の構成は、他の実施の形態と同様に、基本的に第1の実施の形態におけるそれと同じである。このことから、第1の実施の形態で付した符号をそのまま用いて説明を行うことにする。
【0073】
第4の実施の形態では、上記他の実施の形態と同じく、楽曲データ、及びフレーズデータを扱っている。その他に、時系列データ、ノートデータ、及びフレーズブロックデータを扱っている。それらは全てRAM102に格納されるデータである。それら各データは以下のようなものである。
【0074】
図15は、第4の実施の形態で扱われる楽曲データの構成を説明する図である。
その楽曲データは、I/F106を介して読み込み、RAM102に格納されるものである。楽曲の演奏内容を音符単位で示す音符データは、図中、括弧を付して表記の「MidiEvent」で表している。その音符データMidiEventは、データiTime、iType、iGate、Pitch、及びpNextの、の各データを備えた構成となっている。データiTypeは、音符データMidiEventの種類を表すものである。楽音の発音を指示する種類(ノートデータ)では0、テンポを指定する種類(テンポデータ)では1となっている。
【0075】
図16は、第4の実施の形態で扱われる時系列データの構成を説明する図である。
その時系列データNoteGroupは、上記別データに相当するものである。対応する1つ以上の音符による発音(演奏)開始ティックを示すデータITime、その終了ティックを示すデータITerm、対応する時系列データがグループ化されているか否かを示すフラグであるデータiGroupFlag、対応するノートデータへのポインタとなるインデックス値であるデータNoteEv、次の時系列データへのポインタとなるインデックス値であるデータNext、前の時系列データへのポインタとなるインデックス値であるデータprev、の各データから構成される。データNoteEvは、対応するノートデータ数分、存在する。
【0076】
図17は、ノートデータの構成を説明する図である。
そのノートデータNoteは、対応する音符データMidiEventへのポインタとなるインデックス値であるデータpEv、そのピッチを示すデータPitch、次のノートデータNoteのインデックス値であるデータnext、前のノートデータNoteのインデックス値であるデータprev、の各データから構成される。
【0077】
図18は、フレーズ管理用データの構成を説明する図である。図18(a)はフレーズデータPhrase、図18(b)はフレーズブロックデータPhBlock、の構成をそれぞれ表している。
【0078】
フレーズデータPhraseは、対応するフレーズの発音(演奏)開始ティックを示すデータITime、その終了ティックを示すデータITerm、フレーズの切れ目(区切り)の種類(分類)を示すデータiType、関連するフレーズデータのなかで先頭のもののインデックス値であるデータpFirst、その最後のもののインデックス値であるデータpEnd、次のフレーズデータPhraseのインデックス値であるデータnext、前のフレーズデータPhraseのインデックス値であるデータprev、の各データから構成される。
【0079】
フレーズブロックデータPhBlockは、関連付けられたフレーズの数であるデータiPhrase、そのなかで先頭に位置するフレーズデータPhraseのインデックス値であるデータpFirst、次のフレーズブロックデータPhBlockのインデックス値であるデータnext、前のフレーズブロックデータPhBlockのインデックス値であるデータprev、の各データから構成される
本実施の形態では、図15に示す楽曲データから図16〜図18に示す各データを生成し、構造解析を行うようになっている。以降は、図19〜図24に示す各種処理のフローチャートを参照して、第4の実施の形態による楽曲構造解析装置の動作について詳細に説明する。
【0080】
図19は、構造解析処理のフローチャートである。始めに図19を参照して、その解析処理について詳細に説明する。その解析処理は、CPU101がROM103に格納されたアプリケーションを実行することで実現される。
【0081】
そのアプリケーションは起動されると、先ず、ステップSJ1で例えばI/F106により記録媒体駆動装置にセットされた記録媒体から楽曲データの読み込みを行い、図16に示すようなデータ構成の時系列データNoteGroupを生成してRAM102に格納する時系列データの生成処理を実行する。その後に移行するステップSJ2では、フレーズ分割処理を実行する。その実行後、一連の処理を終了する。
【0082】
図20は、上記ステップSJ1として実行される時系列データの生成処理のフローチャートである。次に図20を参照して、その生成処理について詳細に説明する。図16に示す時系列データNoteGroup、及び図17に示すノートデータNoteは、その生成処理の実行によって生成される。
【0083】
先ず、ステップSK1では、各種変数を対象にした初期化を行う。変数ngr、ntmp、me、及びphtmpなどにはRAM102の対応する領域のなかで先頭に位置するデータを指定するためのインデックス値が代入される。それに続くステップSK2では、変数meの値で指定される音符データMidiEventのデータpNextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSK3に移行する。
【0084】
ステップSK3では、変数ITProgに、変数meの値で指定される音符データMidiEventのデータITimeの値を代入し、変数nHarmに、ノートデータNoteを格納できる空きエリアのインデックス値を代入する。次のステップSK4では、変数ngrの値で指定される時系列データNoteGroupのデータNoteEvとして変数nHarmの値、そのデータITimeとして変数ITProgの値、そのデータITermとしてMidiEvent[me].IGateの値に変数ITProgの値を加算した値、をそれぞれ設定する。変数nHarmの値で指定されるノートデータNoteでは、データpEvとして変数meの値、データpitchとしてMidiEvent[me].Pitchの値、データprevとして変数nTmpの値、それぞれ設定する。変数nTmpの値で指定されるノートデータNoteのデータnextとしては変数nHarmの値を設定する。それらデータの設定(対応する領域内へのデータの格納)を行い、更に変数nTmpに変数nHarmの値を代入した後はステップSK5に移行する。
【0085】
ステップSK5では、変数ITProgの値からMidiEvent[MidiEvent[me].pNext].ITimeの値を引いた値の絶対値が定数NOTEONOFFSET未満か否か判定する。定数NOTEONOFFSETは和音の構成音間で許容範囲とする発音開始ティックの時間間隔として定めたものである。このことから、その絶対値が示す時間間隔が許容範囲内であった場合、判定はYESとなってステップSK6に移行し、そうでない場合には、判定はNOとなり、ステップSK11で変数meにMidiEvent[me].pNextの値を代入してから上記ステップSK2に戻る。
【0086】
ステップSK6では、変数meHarmに、MidiEvent[me].pNextの値を代入し、変数nHarmに、ノートデータNoteを格納できる空きエリアのインデックス値を代入する。その後に移行するステップSK7では、変数Tに、MidiEvent[meHarm].ITimeの値にMidiEvent[meHarm].IGateの値を加算した値を代入し、その変数Tの値がNoteGroup[ngr].ITermの値より大きければ、そのNoteGroup[ngr].ITermとして変数Tの値を設定する。ステップSK8にはその後に移行する。
【0087】
ステップSK8では、変数nHarmの値で指定されるノートデータNoteにおいて、データpEvとして変数meの値、データpitchとしてMidiEvent[me].Pitchの値、データprevとして変数nTmpの値、をそれぞれ設定する。変数nTmpの値で指定されるノートデータNoteのデータnextとしては変数nHarmの値を設定する。続くステップSK9では、NoteGroup[ngr].NoteEvとして変数meHarmの値を追加し、データNoteEvを対応する音符のピッチ順にソートする。その後は、ステップSK10に移行して、変数meに変数meHarmの値、変数ntmpに変数nHarmの値をそれぞれ代入した後、上記ステップSK5に戻る。それにより、和音の構成音と見なす複数の音符は1つの時系列データNoteGroupにより管理する。
【0088】
図21は、図19に示す構造解析処理内でステップSJ2として実行されるフレーズ分割処理のフローチャートである。次に図21を参照して、その分割処理について詳細に説明する。
【0089】
先ず、ステップSL1では、変数ngRefに時系列データNoteGroupのなかで先頭のものを指定するインデックス値を代入する。続くステップSL2では、NoteGroup[ngRef].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSL3に移行する。
【0090】
ステップSL3では、変数ngSrcに、変数ngRefの値より規定数先の時系列データNoteGroupのデータnextの値を代入する。次のステップSL4では、NoteGroup[ngSrc].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSL9で変数ngRefに、NoteGroup[ngRef].nextの値を代入してから上記ステップSL2に戻る。そうでない場合には、判定はYESとなってステップSL5に移行する。上記規定数とは定数MarkingNotesである。
【0091】
ステップSL5では、変数iMarkCntに0を代入する。続くステップSL6では、先頭位置検索処理を実行する。その後に移行するステップSL7では、変数iMarkCntの値が0でないか否か判定する。その値が0であった場合、判定はNOとなってステップSL9に移行する。そうでない場合には、判定はYESとなり、ステップSL8でグループ化処理を実行した後、上記ステップSL2に戻る。
【0092】
図22は、上記ステップSL6として実行される先頭位置検索処理のフローチャートである。次にその検索処理について、図22に示すそのフローチャートを参照して詳細に説明する。
【0093】
先ず、ステップSM1では、NoteGroup「ngSrc].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はYESとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSM2に移行する。
【0094】
ステップSM2では、変数jdgに論理値TRUEを代入する。続くステップSM3では、変数iに定数MarkingNotesを代入する。その次のステップSM4では、変数ngReftmpに変数ngRefの値、変数ngSrctmpに変数ngSrcの値をそれぞれ代入する。その代入後に移行するステップSM5では、変数jdgの値がTRUEであり、且つ変数iの値が0より大きいか否か判定する。変数jdgの値がTRUEでないか、或いは変数iの値が0以下であった場合、判定はNOとなってステップSM16に移行する。そうでない場合には、つまり変数jdgの値がTRUEであり、且つ変数iの値が0より大きい場合には、判定はYESとなってステップSM6に移行する。
【0095】
ステップSM6では、NoteGroup「ngSrctmp].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSM15で変数jdgにFALSEを代入し、更にステップSM14で変数iの値をデクリメントした後、上記ステップSM5に戻る。そうでない場合には、判定はYESとなってステップSM7に移行する。
【0096】
ステップSM7では、NoteGroup[ngReftmp].NoteEvの値を変数RefNotetmpに代入し、NoteGroup[ngSrctmp].NoteEvの値を変数SrcNotetmpに代入する。その後に移行するステップSM8では、変数ngReftmpの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「EvNoteGroup[ngReftmp]≠NULL」と表記)、或いは変数ngSrctmpの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「EvNoteGroup[ngSrctmp]≠NULL」と表記)が無いか否か判定する。それらのうちの少なくとも一方の時系列データNoteGroupに他のデータNoteEvが存在しなかった場合、判定はNOとなり、ステップSM11に移行する。そうでない場合には、つまりそれの両方に他のデータNoteEvが存在している場合には、判定はYESとなってステップSM9に移行する。
【0097】
ステップSM9では、変数jdgの値がTRUEであり、且つNote[RefNotetmp].pitchの値がNote[SrcNotetmp].pitchの値と等しければ変数jdgにTRUEを代入する。そうでなければFALSEを代入する。次のステップSM10では、Note[RefNotetmp].nextの値を変数RefNotetmp、Note[SrcNotetmp].nextの値を変数SrcNotetmpにそれぞれ代入する。その代入後は上記ステップSM8に戻る。それにより、データNoteEvが複数、存在している時系列データNoteGroup間では、各データNoteEv毎にその値で指定される音符間のピッチのチェックを行う。
【0098】
一方、ステップSM11では、変数jdgの値がTRUEであり、且つNoteGroup[ngReftmp].ITimeの値からNoteGroup[ngRef].ITimeの値を引いた値に対し、NoteGroup[ngSrctmp].ITimeの値からNoteGroup[ngSrc].ITimeの値を引いた値を減算して得られる値の絶対値が定数StartTickRange未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。次のステップSM12では、変数jdgの値がTRUEであり、且つ変数ngReftmp、ngSrctmpの各値で指定される時系列データNoteGroupで示されるゲートタイムの比を1から引いた値の絶対値が定数GateTimeRatio未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。ステップSM13にはその後に移行して、NoteGroup[ngReftmp].nextの値を変数ngReftmp、NoteGroup[ngSrctmp].nextの値を変数ngSrctmp、にそれぞれ代入する。ステップSM14にはその代入後に移行する。
【0099】
上記ステップSM5の判定がNOとなって移行するステップSM16では、変数jdgの値がTRUEか否か判定する。その値がTRUEであった場合、判定はYESとなってステップSM17に移行する。そうでない場合には、判定NOとなり、ステップSM22で変数ngSrcに、NoteGroup[ngSrc].nextの値を代入した後、上記ステップSM1に戻る。
【0100】
ステップSM17では、変数iMarkCntの値が0か否か判定する。その値が0であった場合、判定はYESとなり、ステップSM18でフレーズデータ登録処理を実行し、次のステップSM19で変数iMarkCntの値をインクリメントし、その次のステップSM20でフレーズデータ登録処理を実行し、更にステップSM21で変数ngSrcに、変数ngSrcの値より規定数先の時系列データNoteGroupのデータne
xtの値を代入する。その後は上記ステップSM1に戻る。
【0101】
上記フレーズデータ登録処理は、ステップSM18では大元のフレーズを対象にして、ステップSM20ではそれと関連付けるフレーズを対象にして行われる。次にその登録処理について、図23に示すそのフローチャートを参照して詳細に説明する。その登録処理を実行することにより、図18(a)に示すフレーズデータPhrase、図18(b)に示すフレーズブロックデータPhBlockが生成される。
【0102】
先ず、ステップSN1では、フレーズデータPhraseのなかで先頭に位置しているもののインデックス値を変数phに代入する。次のステップSN2では、変数phnewに、フレーズデータPhraseが格納されていないエリア(空バッファ)のインデックス値、変数phbnewに、フレーズブロックデータPhBlockが格納されていないエリア(空バッファ)のインデックス値をそれぞれ代入する。その後はステップSN3に移行する。
【0103】
ステップSN3では、変数iMarkCntの値が0か否か判定する。その値が0でなかった場合、判定はNOとなってステップSN9に移行する。そうでない場合には、判定はYESとなってステップSN4に移行する。
【0104】
ステップSN4では、変数nginsに変数ngRefの値、変数ngTermに変数ngReftmpの値、をそれぞれ代入する。続くステップSN5では、Phrase[pbnew].ITimeとしてNoteGroup[ngins].ITimeの値、Phrase[phnew].ITermとしてNoteGroup[ngins].ITermの値、Phrase[phnew].iTypeとして0、Phrase[phnew].pFirstとして変数nginsの値、Phrase[phnew].pEndとして変数ngTermの値、をそれぞれ設定し、変数phbに変数phbnewの値を代入する。ステップSN6には、その後に移行する。
【0105】
ステップSN6では、Phrase[Ph].nextの値がNULLでなく、且つPhrase[Ph].ITimeの値がPhrase[ngins].ITimeの値より大きいか否か判定する。Phrase[Ph].nextの値がNULLか、或いはPhrase[Ph].ITimeの値がPhrase[ngins].ITimeの値以下であった場合、判定はNOとなり、ステップSN7で変数phにPhrase[ph].nextの値を代入した後、そのステップSN6に戻る。そうでない場合には、つまりPhrase[Ph].nextの値がNULLでなく、且つPhrase[Ph].ITimeの値がPhrase[ngins].ITimeの値より大きい場合には、判定はNOとなり、ステップSN8で変数phnewの値で指定されるフレーズデータPhraseを変数phの値で指定されるフレーズデータPhraseより後になるように挿入させる形で格納した後、一連の処理を終了する。
【0106】
上記ステップSN3の判定がNOとなって移行するステップSN9では、PhBlock[phbnew].prevとして変数phbの値、PhBlock[phb].nextとして変数phbnewの値、をそれぞれ設定し、変数phbに変数phbnewの値を代入し、PhBlock[phb].pFirstとして変数phrefの値を設定する。その後は、ステップSN10で変数nginsに変数ngSrc、変数ngTermに変数ngSrctmpの値をそれぞれ代入してからステップSN5に移行する。
【0107】
図24は、図21に示すグループ分割処理内でステップSL8として実行されるグループ化処理のフローチャートである。次にそのグループ化処理について、図24に示すそのフローチャートを参照して詳細に説明する。
【0108】
先ず、ステップSP1では、変数ngReftmpに、Phrase[phRef].pEndの値、変数phSrcに変数phRefの値をそれぞれ代入する。次のステップSP2では、Phrase[phsrc].nextの値がNULLでないか否か判定する。その値がNULLだった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSP3に移行する。
【0109】
ステップSP3では、変数phSrcにPhrase[phRef].nextの値、変数ngSrcにPhrase[phSrc].pFirstの値、変数ngSrctmpにPhrase[phSrc].pEndの値、変数jdgにTRUE、をそれぞれ代入する。その代入後に移行するステップSP4では、変数jdgの値がTRUEであり、且つ、NoteGroup[ngSrctmp].nextの値がNULLでないか否か判定する。変数jdgの値がTRUEでないか、或いはNoteGroup[ngSrctmp].nextの値がNULLであった場合、判定はNOとなってステップSP16に移行し、図9に示すフレーズデータへのグループ登録処理と同様にしてフレーズデータPhraseの更新を行った後、上記ステップSP2に戻る。そうでない場合には、つまり変数jdgの値がTRUEであり、且つ、NoteGroup[ngSrctmp].nextの値がNULLでない場合には、判定はYESとなってステップSP5に移行する。
【0110】
ステップSP5〜SP10では、図22に示すステップSM7〜SM12と同様の処理が行われる。ステップSP10の処理の実行後に移行するステップSP11では、NoteGroup[ngSrctmp].ITimeの値が、Phrase[Phrase[phSrc].next].ITimeの値以上か否か判定する。前者が後者以上であった場合、判定はYESとなり、ステップSP12でPhrase[Phrase[phSrc].next].ITypeとして2を設定した後、ステップSP13に移行する。そうでない場合には、判定はNOとなってそのステップSP13に移行する。
【0111】
ステップSP13では、NoteGroup[ngReftmp].ITimeの値が、Phrase[phSrc].ITimeの値以上か否か判定する。前者が後者以上であった場合、判定はYESとなり、ステップSP14でPhrase[phSrc].ITypeとして2を設定し、変数phSrcに、Phrase[phSrc].nextの値を代入する。そうでない場合には、判定はNOとなってステップSP15に移行する。そのステップSP15では、変数ngReftmpにNoteGroup[ngReftmp].nextの値、変数ngSrctmpにNoteGroup[ngSrctmp].nextの値、をそれぞれ代入する。その代入後は上記ステップSP4に戻る。
<第5の実施の形態>
上記第1〜第4の実施の形態では、類似性に着目してフレーズ分割を行っている。これに対し、第5の実施の形態は、分割時とは異なる視点で、分割したフレーズ間の関連性(類似性)を更に解析するようにしたものである。ここでは、リズム、及び転調の2つに着目して関連性の解析を行うようにしている。そのような解析を行い、その結果を図28に示すようにして提示することにより、楽曲構造をより具体的、且つ容易に理解できるようになる。
【0112】
第5の実施の形態における楽曲構造解析装置の構成は、他の実施の形態と同様に、基本的に第1の実施の形態におけるそれと同じである。このことから、第1の実施の形態で付した符号をそのまま用いて説明を行うことにする。
【0113】
第5の実施の形態では、上記第4の実施の形態で扱うデータの他に、フレーズ関連性データを更に扱っている。その関連性データは、フレーズ間の関連性の解析結果を管理するために用意したものである。
【0114】
図25は、フレーズ管理用データの構成を説明する図である。図25(a)はフレーズブロックデータ、図25(b)はフレーズ関連性データのデータ構成をそれぞれ示している。
【0115】
図25(a)に示すように、第5の実施の形態では、フレーズブロックデータPhBlockは、第4の実施の形態からデータpRelationalが追加されている。そのデータpRelationalは、関連性の解析を行った最初のフレーズデータPhraseのインデックス値である。データpFirstとしては、対応するフレーズデータPhraseのインデックス値を格納するようになっている。
【0116】
フレーズ関連性データは図25(b)に示すように、関連性の解析を行った種類を示すデータiType(リズムは1、転調は2)、解析結果である一致性を示すデータiRatio、対応する、関連性を解析したフレーズのフレーズブロックデータPhBlockのインデックス値であるデータRelationalBlock、次の関連性データPhRelationのインデックス値であるデータnext、前の関連性データPhRelationのインデックス値であるprev、の各データから構成される。
【0117】
上記リズム、及び転調の関連性の解析は、ぞれぞれ図26に示すリズム解析処理、図27に示す転調解析処理を実行することで行われる。それらの解析処理は、例えば図19に示す構造解析処理内でステップSJ2のフレーズ分割処理の実行後に実行するようになっている。本実施の形態では、特に詳細な説明は省略するが、それらのうちの一方のみを選択的に実行するようにしている。以降、それら解析処理について、図26、及び図27を参照して詳細に説明する。
【0118】
始めに、図26を参照してリズム解析処理について詳細に説明する。
先ず、ステップSQ1では、変数の初期化を行う。その初期化により、各データのなかで着目するものを管理するための変数には、そのデータのなかで先頭に位置するもののインデックス値が代入される。その後に移行するステップSQ2では、PhBlock[phbRef].nextの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ここで一連の処理を終了する。そうでない場合には、判定はYESとなってステップSQ3に移行する。
【0119】
ステップSQ3では、変数phbSrcに、Phrase[phbRef].nextの値を代入する。その次に移行するステップSQ4では、変数phbSrcの値がNULLでないか否か判定する。その値がNULLであった場合、判定はNOとなり、ステップSQ17でPhBlock[phbRef].nextの値を変数phbRefに代入してから上記ステップSQ2に戻る。そうでない場合には、判定はYESとなってステップSQ5に移行する。
【0120】
ステップSQ5では、Phrase[PhBlock[phbRef].pFirst].pFirstの値(変数phrRefの値で対応するフレーズブロックデータPhBlockが指定されるフレーズの先頭位置に存在する時系列データNoteGroupのインデックス値)を変数ngRefに、Phrase[PhBlock[phbSrc].pFirst].pFirstの値を変数ngSrcに、それぞれ代入する。続くステップSQ6では、変数ngRefの値を変数ngReftmpに、変数ngSrcの値を変数ngSrctmpに、それぞれ代入し、変数iOrgCnt、及びiHitCntにそれぞれ0を代入する。その後は、ステップSQ7で変数iOrgCntの値をインクリメントし、変数jdgにTRUEを代入してからステップSQ8に移行する。
【0121】
ステップSQ8では、変数jdgの値がTRUEであり、且つNoteGroup[ngReftmp].ITIMEの値からNoteGroup[ngRef].ITimeの値を引いた値に対し、NoteGroup[ngSrctmp].ITimeの値からNoteGroup[ngSrc].ITimeの値を引いた値を減算して得られる値の絶対値が定数StartTickRange未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。続くステップSQ9では、変数jdgの値がTRUEであり、且つ変数ngReftmp、ngSrctmpの各値で指定される時系列データNoteGroupで示されるゲートタイムの比を1から引いた値の絶対値が定数GateTimeRatio未満であれば変数jdgにTRUEを代入する。そうでなければFALSEを代入する。その後はステップSQ10に移行する。
【0122】
ステップSQ10では、変数jdgの値がTRUEか否か判定する。その値がTRUEであった場合、判定はYESとなり、ステップSQ11で変数iHitCntの値をインクリメントした後、ステップSQ12に移行する。そうでない場合には、判定はNOとなってそのステップSQ12に移行する。
【0123】
ステップSQ12では、Phrase[PhBlock[phbRef].pFirst].pEndの値が変数ngReftmpの値と等しくなく、且つPhrase[PhBlock[phbSrc].pFirst].pEndの値が変数ngSrctmpの値と等しいか否か判定する。それらが共に等しくない場合、判定はYESとなり、ステップSQ13でNoteGroup[ngReftmp].nextの値を変数ngReftmpに、NoteGroup[ngSrctmp].nextの値を変数ngSrctmpに、それぞれ代入した後、上記ステップSQ7に戻る。それにより、フレーズ間での対比を継続して行う。そうでない場合には、つまり少なくとも何れか一方が等しい場合には、判定はNOとなってステップSQ14に移行する。
【0124】
ステップSQ14では、変数phrRに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrR].iTypeとして1を設定し、PhRelation[phrR].RelationalBlockとして変数phbSrcの値を設定し、PhRelation[phrR].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSQ15に移行する。
【0125】
ステップSQ15では、変数phrSに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrS].iTypeとして1を設定し、PhRelation[phrS].RelationalBlockとして変数phbRefの値を設定し、PhRelation[phrS].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSQ16に移行して、PhBlock[phbSrc].nextの値を変数phbSrcに代入する。上記ステップSQ4にはその後に移行する。
【0126】
次に、図27を参照して転調解析処理について詳細に説明する。
図27では、図26に示すリズム解析処理と処理内容が同じ、或いは基本的に同じものには同一の符号を付してある。ここでは、図26から異なる部分に着目して説明することとする。
【0127】
図27の転調解析処理では、ステップSQ10の判定がYESとなるとステップSR1に移行する。そのステップSR1では、NoteGroup[ngRef].NoteEvの値を変数RefNotetmpに代入し、NoteGroup[ngSrc].NoteEvの値を変数SrcNotetmpに代入する。次のステップSR2では、変数ngRefの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「Note[RefNotetmp]≠NULL」と表記)、或いは変数ngSrcの値で指定される時系列データNoteGroupに他のデータNoteEvが無いか(図中「Note[SrcNotetmp]≠NULL」と表記)が無いか否か判定する。それらのうちの少なくとも一方の時系列データNoteGroupに他のデータNoteEvが存在しなかった場合、判定はNOとなり、ステップSQ12に移行する。そうでない場合には、つまりそれの両方に他のデータNoteEvが存在している場合には、判定はYESとなってステップSR3に移行する。
【0128】
ステップSR3では、Note[RefNotetmp].pitchの値からNote[SrcNotetmp].pitchの値を引いた値を変数iDifに代入し、配列変数iHitCntの12から変数iDifの値を引いた値で指定される要素iHitCnt[12−iDif]の値をインクリメントする。続くステップSR4では、変数ngRefの値で指定される時系列データNoteGroupに他のデータNoteEvが存在すればNote[RefNotetmp].nextの値を変数RefNotetmp、同様にNote[SrcNotetmp].nextの値を変数SrcNotetmpにそれぞれ代入する。その代入後は上記ステップSR2に戻る。
【0129】
転調解析処理では、ステップSQ12の判定がNOとなるとステップSR5に移行し、配列変数iHitmaxの要素のなかで値が最も大きい要素を指定する値を変数iHitMaxに代入する。次のステップSR6では、変数phrRに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrR].iTypeとして2を設定し、PhRelation[phrR].RelationalBlockとして変数phbSrcの値を設定し、PhRelation[phrR].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSR7に移行する。
【0130】
ステップSR7では、変数phrSに、フレーズ関連性データPhBlockが格納されていないエリアのインデックス値を代入し、PhRelation[phrS].iTypeとして2を設定し、PhRelation[phrS].RelationalBlockとして変数phbRefの値を設定し、PhRelation[phrS].Ratioとして、変数iHitCntの値を変数iOrgCntの値で割った値に100を掛けて得られる値を設定する。その後はステップSQ16に移行する。
【0131】
なお、本実施の形態では、関連性としてリズム、及び転調に着目した解析を行うようにしているが、それら以外の関連性(類似性)に着目した解析を行うようにしても良い。着目する関連性の異なる複数の解析を一度に行えるようにしても良い。また、特許文献1に記載された技術での構造解析を併せて行い、その結果を反映させた形で構造解析を行うようにしても良い。
【0132】
上述したような楽曲構造解析装置を実現させるようなプログラムは、CD−ROM、DVD、或いは着脱自在なフラッシュメモリ等の記録媒体に記録させて配布しても良い。公衆網等の通信ネットワークを介して、そのプログラムの一部、若しくは全部を配信するようにしても良い。そのようにした場合には、ユーザーはプログラムを取得してデータ処理装置にロードすることにより、その装置に本発明を適用させることができる。このことから、記録媒体は、プログラムを配信する装置がアクセスできるものであっても良い。
【図面の簡単な説明】
【0133】
【図1】第1の実施の形態による楽曲構造解析装置の構成を説明する図である。
【図2】楽曲データの構成を説明する図である。
【図3】フレーズデータの構成を説明する図である。
【図4】構造解析処理のフローチャートである。
【図5】フレーズ分割処理のフローチャートである。
【図6】先端位置検索処理のフローチャートである。
【図7】フレーズデータの登録処理のフローチャートである。
【図8】グループ化処理のフローチャートである。
【図9】フレーズデータへのグループ登録処理のフローチャートである。
【図10】楽曲の分割方法を説明する図である。
【図11】グループ化処理のフローチャートである(第2の実施の形態:抜粋)。
【図12】フレーズ分割処理のフローチャートである(第3の実施の形態)。
【図13】端数処理のフローチャートである。
【図14】楽曲の構造解析結果の表示例を説明する図である(その1)。
【図15】楽曲データの構成を説明する図である(第4の実施の形態)。
【図16】時系列データの構成を説明する図である。
【図17】ノートデータの構成を説明する図である。
【図18】フレーズ管理用データの構成を説明する図である。
【図19】構造解析処理のフローチャートである(第4の実施の形態)。
【図20】時系列データの生成処理のフローチャートである。
【図21】フレーズ分割処理のフローチャートである(第4の実施の形態)。
【図22】先端位置検索処理のフローチャートである(第4の実施の形態)。
【図23】フレーズデータ登録処理のフローチャートである(第4の実施の形態)。
【図24】グループ化処理のフローチャートである(第4の実施の形態)。
【図25】フレーズ管理用データの構成を説明する図である(第5の実施の形態)。
【図26】リズム解析処理のフローチャートである(第5の実施の形態)。
【図27】転調解析処理のフローチャートである(第5の実施の形態)。
【図28】楽曲の構造解析結果の表示例を説明する図である(その2)。
【符号の説明】
【0134】
101 CPU
102 RAM
103 ROM
104 入力装置
105 表示装置
106 インターフェース(I/F)
【特許請求の範囲】
【請求項1】
楽曲の構造の解析を行う楽曲構造解析装置において、
前記楽曲の演奏内容を音符単位で示す演奏情報を取得する演奏情報取得手段と、
前記演奏情報取得手段が取得した演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、前記楽曲から演奏内容が類似する複数の演奏区間を抽出する構造解析手段と、
を具備することを特徴とする楽曲構造解析装置。
【請求項2】
前記構造解析手段は、音符による発音時間の相違を考慮して前記解析を行う、
ことを特徴とする請求項1記載の楽曲構造解析装置。
【請求項3】
前記構造解析手段は、前記演奏区間として抽出されない部分に存在する音符のなかで所定の条件を満たす音符は該演奏区間に含める、
ことを特徴とする請求項1、または2記載の楽曲構造解析装置。
【請求項4】
楽曲の構造の解析を行う楽曲構造解析装置に実行させるプログラムであって、
前記楽曲の演奏内容を音符単位で示す演奏情報を取得する機能と、
前記取得する機能により取得した演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、前記楽曲から演奏内容が類似する複数の演奏区間を抽出する機能と、
を実現させるためのプログラム。
【請求項1】
楽曲の構造の解析を行う楽曲構造解析装置において、
前記楽曲の演奏内容を音符単位で示す演奏情報を取得する演奏情報取得手段と、
前記演奏情報取得手段が取得した演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、前記楽曲から演奏内容が類似する複数の演奏区間を抽出する構造解析手段と、
を具備することを特徴とする楽曲構造解析装置。
【請求項2】
前記構造解析手段は、音符による発音時間の相違を考慮して前記解析を行う、
ことを特徴とする請求項1記載の楽曲構造解析装置。
【請求項3】
前記構造解析手段は、前記演奏区間として抽出されない部分に存在する音符のなかで所定の条件を満たす音符は該演奏区間に含める、
ことを特徴とする請求項1、または2記載の楽曲構造解析装置。
【請求項4】
楽曲の構造の解析を行う楽曲構造解析装置に実行させるプログラムであって、
前記楽曲の演奏内容を音符単位で示す演奏情報を取得する機能と、
前記取得する機能により取得した演奏情報が示す部分的な演奏内容の類似性に着目した解析を行い、前記楽曲から演奏内容が類似する複数の演奏区間を抽出する機能と、
を実現させるためのプログラム。
【図1】
【図2】
【図3】
【図4】
【図5】
【図6】
【図7】
【図8】
【図9】
【図10】
【図11】
【図12】
【図13】
【図14】
【図15】
【図16】
【図17】
【図18】
【図19】
【図20】
【図21】
【図22】
【図23】
【図24】
【図25】
【図26】
【図27】
【図28】
【図2】
【図3】
【図4】
【図5】
【図6】
【図7】
【図8】
【図9】
【図10】
【図11】
【図12】
【図13】
【図14】
【図15】
【図16】
【図17】
【図18】
【図19】
【図20】
【図21】
【図22】
【図23】
【図24】
【図25】
【図26】
【図27】
【図28】
【公開番号】特開2006−85090(P2006−85090A)
【公開日】平成18年3月30日(2006.3.30)
【国際特許分類】
【出願番号】特願2004−272498(P2004−272498)
【出願日】平成16年9月17日(2004.9.17)
【出願人】(000001443)カシオ計算機株式会社 (8,748)
【Fターム(参考)】
【公開日】平成18年3月30日(2006.3.30)
【国際特許分類】
【出願日】平成16年9月17日(2004.9.17)
【出願人】(000001443)カシオ計算機株式会社 (8,748)
【Fターム(参考)】
[ Back to top ]