(57)【特許請求の範囲】
【請求項１】
一時にはそれぞれ１つの楽音の生成を担当する、複数の楽音生成手段と、
発音指示を受けて直ちに、発音指示がなされた楽音を、前記複数の楽音生成手段のうちのいずれかに対して発音開始時の特質で生成開始させる第１の発音制御を行なう楽音生成開始手段と、
楽音生成中の前記楽音生成手段それぞれに対して、該楽音生成手段で生成中の楽音の特質を変化させる第２の発音制御を行なうサービス手段と、
所定のサービス周期毎に一周期の経過を通知するサービス周期通知手段と、
前記楽音生成手段で生成中の楽音の特質が、当該楽音生成手段に対して前記第１の発音制御が行なわれた時点以降最初に、前記サービス通知手段からの一周期の経過の通知を受けた１回目の時点では、前記サービス周期一周期の２分の１の時間が経過した時点の特質に変化し、当該１回目の時点経過後は、前記サービス周期毎に順次一周期後の特質に変化するように、前記サービス手段を制御するサービス制御手段とを備えたことを特徴とする楽音生成装置。
【発明の詳細な説明】
【０００１】
【発明の属する技術分野】
本発明は、音源を備え、楽音の発音指示を受けて音源に対し発音制御を行なうことにより楽音を生成する楽音生成装置に関する。
【０００２】
【従来の技術】
音源に対する発音制御は大きく分けると２つの部分からなる。一つは「初期発音」、もう一つは「ボイスサービス」である。以下、「ボイスサービス」のことを単に「サービス」と称することもある。これらの初期発音、ボイスサービスの処理は、一般にＣＰＵによって行なわれる。
【０００３】
初期発音とは、発音要求（ノート・オン）に対応してアサインされた、いわゆるボイスに対して、その発音要求の示す音高（押鍵による発音キーナンバ）、強さ（押鍵ベロシティ）などに基づいて発音処理を施す（音高、音質、音量などの楽音の特質パラメータを求めて与える）ことである。ここで、「ボイス」とは一時に一つの楽音を生成するための楽音生成手段のことを指す。楽音生成回路には、複数の楽音を同時に生成可能なように複数のボイスが設けられている。発音要求に応じていずれかのボイスを選択しその選択したボイスに発音要求を割り当てることを「アサイン」と称する。また、そのアサインを行なう手段を「アサイナ」と称する。後述する本発明の実施形態ではアサイナタスクがアサインを行なうので、以後の説明ではアサイナタスクのことを単にアサイナと称することもある。
【０００４】
サービスは、一定時間ごとに各ボイスの音高、音質、音量などの楽音の特質パラメータを変化させてボイスに供給し、そのボイスで生成中の楽音に時間的な特質の変化をもたらせる処理である。
【０００５】
具体的には、これら初期発音およびサービスによってエンベロープやＬＦＯを生成しこれに基づきボイスに対して楽音の特質パラメータを制御することになる。すなわち、サービスによってエンベロープやＬＦＯの値が時間的に変化する。
【０００６】
マルチタスク構成で複数のボイスを制御する場合、これら初期発音とサービスは異なるタスクに分割されて実装されることが多い。その理由は、
（１）サービスは、現在発音中の全てのボイスについて音高、音質、音量を求めてボイスに与える（通常、各ボイスあたり数ミリ秒〜十数ミリ秒間隔）ため、定常的な負荷が大きい。しかしある程度処理が遅れてもさほど不自然に聞こえない。
【０００７】
（２）一方、初期発音処理は発音要求（ノート・オン）を受けた時のみ行なえばよいので、定常負荷は少なくて済むが、ノート・オンを受けてから発音開始までの時間が遅れると不自然であり、楽器として演奏困難になる。
という異なった性質によるものである。
【０００８】
そこで、リアルタイム・モニタなどを実装してマルチタスク制御をすることが考えられる。その際は、サービス処理タスクは定期的にサービス処理を行ない、それよりも高い優先順位で初期発音を行なう発音タスクを実装する。そうすることでどんなにサービスの負荷が重いときでも初期発音が最優先で行なわれ、聴感上不自然さが少ない。
【０００９】
尚、以後の説明では、初期発音を行なうタスクを「発音タスク」、定期的なサービスを行なうタスクを「サービスタスク」と称する。また、以後の説明では「リアルタイム・モニタ」のことを単に「モニタ」と称することもある。
【００１０】
従来の方法について説明する。
【００１１】
図１７は、従来の発音タスクを示すフローチャートである。
【００１２】
このフローチャート中、「発音ボイス番号」は、発音に使用するボイスの番号をいう。また、このフローチャート中の記号の意味は、以下のとおりである。尚、以下に説明する各フローチャート中にそれよりも前に説明したフローチャート中の記号と同一の記号があらわれたときは、同一の記号であっても意味が異なる場合を除き、重複説明は省略することがある。また、各タスク（発音タスクを含む全タスク）で使用される変数は電源投入時に初期化されるものとする。
【００１３】
（ａ）ｖｏｉｃｅ：ボイス番号。発音タスクにおいてはアサイナタスクから与えられたボイス番号を示す。
【００１４】
ｖｏｉｃｅ＝０〜ＭＡＸ＿ＶＯＩＣＥ
但し、ＭＡＸ＿ＶＯＩＣＥはボイス番号の最大値を指す。
【００１５】
（ｂ）ｃｏｕｎｔｅｒ［ｖｏｉｃｅ］：そのｖｏｉｃｅの初期発音以降の経過時間を表現する変数を示す。
【００１６】
（ｃ）ｓｅｒｖ＿ｆｌａｇ［ｖｏｉｃｅ］：そのｖｏｉｃｅが発音中であることを示すフラグである。
【００１７】
実際には、発音タスクよりも上位にＭＩＤＩ受信タスクまたは鍵盤スキャンタスクなどがあり、ＭＩＤＩ受信タスク、鍵盤スキャンタスクなどによって発音要求が検出された場合には、続いてアサイナタスクが起動され、ボイスアサインが行なわれる。または別タスクでなくとも、同様の処理がこの発音タスクの処理の前に行なわれる。ボイスアサインが行なわれた結果、アサイナタスクから発音イベントが発生し、これにより発音タスクが起動される。
【００１８】
尚、ＭＩＤＩ（Ｍｕｓｉｃａｌ  Ｉｎｓｔｒｕｍｅｎｔ  Ｄｉｇｉｔａｌ  Ｉｎｔｅｒｆａｃｅ）は、電子楽器の分野で広範囲に使用されている通信プロトコルである。
【００１９】
図１７に示す発音タスクは、与えられたノート・オン情報を上位タスクから受け取り（ステップ１７＿１）、それに応じた、発音時のエンベロープやＬＦＯを生成し、それに応じた音量、音質、音高のパラメータを求める（ステップ１７＿２）。
【００２０】
またアサイナから指定されたボイスにパラメータを与え、初期発音を行なう（ステップ１７＿３）。
【００２１】
そのあとで、時間カウンタｃｏｕｎｔｅｒ［ｖｏｉｃｅ］を０で初期化し（ステップ１７＿３）、初期発音を終えたことをサービスタスクに知らせるためにフラグｓｅｒｖ＿ｆｌａｇ［ｖｏｉｃｅ］を設定し（ステップ１７＿５）、再びアサイナタスクから発生される発音イベント待ち状態になる。
【００２２】
図１８は、従来のサービスタスクのフローチャートである。このフローチャート中の記号の意味は、以下のとおりである。
【００２３】
（ａ）ｃｎｔ＿ｉｎｃ：サービスタスクの起動周期に対応する時間経過を表わす定数であり、例えば、８ｍＳの時間経過を表す。
【００２４】
実際には、例えば、８ｍＳの周期で発生するタイマ・インタラプトに応じてモニタがタイマ・イベントを発生し、これによりサービスタスクが起動される。
【００２５】
なおサービスタスクは処理終了後に再びタイマ・イベント待ち状態となる。
【００２６】
図１８のサービスタスクでは、ｓｅｒｖ＿ｆｌａｇをスキャンすることで現在発音中のボイス番号がわかるので（ステップ１８＿１，１８＿２，１８＿７，１８＿８）、現在発音中のボイスすべてについて、前回サービスを行なった時刻よりタイマ時間（サービスタスク起動周期）後（ステップ１８＿３）のエンベロープやＬＦＯを求め、これに基づき音高、音質、音量を求め、ボイスに供給する（ステップ１８＿４）。もしもある時点で求めた音量エンベロープの示す音量レベルが０であって、かつエンベロープの全てのフェーズ（アタック、ディケイ、サスティン、リリースなどのエンベロープの各区間）が終了していたら、言い換えると発音が終了したら（ステップ１８＿５）、そのボイスのｓｅｒｖ＿ｆｌａｇをクリアする（ステップ１８＿６）。
【００２７】
尚、エンベロープは各フェーズ毎に時間やレベルの設定が異なるため、ｃｏｕｎｔｅｒを初期発音以後の実経過時間に対応させて時間管理するのではなく、ｃｏｕｎｔｅｒの最大値を決め、各フェーズ毎に指定された時間を経過することによりｃｏｕｎｔｅｒがオーバーフローするようなｃｎｔ＿ｉｎｃ値を、各フェーズ毎に計算で求めてもよい。すなわちこの場合、ｃｏｕｎｔｅｒは初期発音以後の経過時間を表現するのではなく現フェーズ開始以後の相対的な経過時間を表現することになる。もちろんこの場合であっても新たなフェーズがアタックである場合にはｃｏｕｎｔｅｒは初期発音以後の相対的な経過時間を表現することになる。この場合はｃｎｔ＿ｉｎｃは定数ではなく、変数として、各ボイス毎に１フェーズ区間記憶しておく必要がある。
【００２８】
ｃｏｕｎｔｅｒをもとにエンベロープのレベル、フェーズを求めるには例えば以下のような処理を行なう。
【００２９】
図１９に示すように、あるフェーズにおいて、時間Ｔの間にエンベロープのレベルをレベルＬ１からレベルＬ２まで直線的に変化させる場合、フェーズが切換わった時点で時間Ｔからｃｎｔ＿ｉｎｃを求める。具体的には、式
ｃｎｔ＿ｉｎｃ＝ｓｅｒｖｉｃｅ＿ｔｉｍｅ×ｃｏｕｎｔｅｒ＿ｍａｘ／Ｔ
により、ｃｎｔ＿ｉｎｃを求める。但し、ｓｅｒｖｉｃｅ＿ｔｉｍｅはサービスの周期を示す定数、ｃｏｕｎｔｅｒ＿ｍａｘはｃｏｕｎｔｅｒの最大値を示す定数である。ここで、
ｃｏｕｎｔｅｒ＿ｍａｘ≧ｃｏｕｎｔｅｒ≧０
とする。これは「ｃｏｕｎｔｅｒにｃｎｔ＿ｉｎｃをサービスタイム毎に加算しつづけるとＴの時間経過後にｃｏｕｎｔｅｒがオーバーフローする。」ということを意味している。
【００３０】
次にｃｏｕｎｔｅｒを０クリアして、あとはサービスの度にｃｎｔ＿ｉｎｃを加算し、ｃｏｕｎｔｅｒのオーバーフローをチェックする。オーバーフローしていたらそのフェーズは終了したことを示すので次のフェーズに切換える。
【００３１】
オーバーフローしなかった場合、ｃｏｕｎｔｅｒをもとにエンベロープの現在レベルＬを算出する。エンベロープを直線状に変化させる場合には、例えば以下のような処理を行なう。
【００３２】
Ｌ＝ｃｏｕｎｔｅｒ／ｃｏｕｎｔｅｒ＿ｍａｘ＊（Ｌ２−Ｌ１）＋Ｌ１
また、エンベロープを曲線的に変化させる場合には、
Ｌ＝Ｆ（ｃｏｕｎｔｅｒ／ｃｏｕｎｔｅｒ＿ｍａｘ）＊（Ｌ２−Ｌ１）＋Ｌ１
但し、Ｆ（ｔ）は任意の曲線を示す関数テーブル（１≧ｔ≧０）、Ｆ（０）＝０、Ｆ（１）＝１とする。
あるいは、
Ｌ＝Ｆ（ｃｏｕｎｔｅｒ／ｃｏｕｎｔｅｒ＿ｍａｘ）＊（Ｌ１−Ｌ２）＋Ｌ２
但し、Ｆ（ｔ）は任意のカーブを示す関数テーブル（１≧ｔ≧０）、Ｆ（０）＝１、Ｆ（１）＝０とする。
のような処理を行なえばよい。
【００３３】
【発明が解決しようとする課題】
上述した従来の手法では、発音タスクはノート・オンに同期して発音を開始させるが、サービスタスクはノート・オン・タイミングとは無関係に、一定間隔で起動される。そのため、初期発音から１回目のサービスまでの時間がまちまちである。すなわち、演算などの処理速度を無視したとしても、最大、サービスタスクのタイマ時間（サービス時間；サービスタスクの起動時間間隔）分だけ誤差が出る。
【００３４】
ところがサービスタスクでは前回のサービスよりタイマ時間後のエンベロープやＬＦＯを求め、音高、音質、音量を求めるようになっている。つまり初期発音から１回目のサービスまでの実際の経過時間と音高、音質、音量を求める上での経過時間とが異なることとなる。そのためエンベロープのアタック部やＬＦＯのカーブが２回目以降のサービス部分に比べていびつになることが起こり得る。
【００３５】
上記フローのようなアルゴリズムで実装された発音タスクとサービスタスクの間では、発音タスクと１回目のサービスとの時間間隔がまばらになり、そのばらつきは、
０  ≦  ばらつき  ＜  サービス間隔
になる。
【００３６】
エンベロープを例にとって説明する。
【００３７】
例えば今、サービス時間を８ミリ秒、発音開始時から１６ミリ秒で最大レベルに到達し最大レベルを維持することとすると、発音タスクとサービスタスクは、図２０のようになることを想定して、特質パラメータを求める。この図２０の縦軸はエンベロープによって制御される音高、音質、音量などを表わしている。
【００３８】
ところが、サービスタスクは、発音タスクとは無関係に８ミリ秒おきに起動されるため、実際には、図２１に示すように初期発音のタイミングは、サービスの起動タイミングとは一致しない。その結果、例えば図２１に示すタイミングで発音イベントが発生する場合には、エンベロープの形状は、図２２に示すようないびつなものになる。
【００３９】
楽音の、特にアタック部分は、その音色のイメージを決定する上で極めて重要な要素であるが、従来の手法では、上記のような時間誤差が出ることにより、アタックエンベロープの形状が変形してしまい、楽音の劣化が生じていた。尚、上記の説明では、楽音の劣化が顕著な例としてエンベロープを取り上げたが、ＬＦＯの場合も同様である。
【００４０】
この劣化を少なくするためにはタイマ時間間隔を短くするという手法が考えられるが、単に短くするだけではタイマ時間内に全ボイスのサービス処理が間に合わなくなり、アタック以外のエンベロープ形状にも悪影響を与えてしまうという問題がある。高速に処理のできるＣＰＵを使用すればその問題は回避できるが、その場合ハードウェアのコストが上がってしまうという問題が発生する。
【００４１】
本発明は、上記事情に鑑み、比較的安価なＣＰＵを用いても、従来と比べ処理遅れを少なく押えることができ、エンベロープの形状やＬＦＯの形状をより忠実に発生することのできる楽音生成装置を提供することを目的とする。
【００４２】
【課題を解決するための手段】
本発明の楽音生成装置は、
一時にはそれぞれ１つの楽音の生成を担当する、複数の楽音生成手段、
発音指示を受けて直ちに、発音指示がなされた楽音を、上記複数の楽音生成手段のうちのいずれかに対して発音開始時の特質で生成開始させる第１の発音制御を行なう楽音生成開始手段、
楽音生成中の楽音生成手段それぞれに対して、楽音生成手段で生成中の楽音の特質を変化させる第２の発音制御を行なうサービス手段、
所定のサービス周期毎に一周期の経過を通知するサービス周期通知手段、
楽音生成手段で生成中の楽音の特質が、その楽音生成手段に対して上記第１の発音制御が行なわれた時点以降最初に、上記サービス通知手段からの一周期の経過の通知を受けた１回目の時点では、上記サービス周期一周期の２分の１の時間が経過した時点の特質に変化し、その１回目の時点経過後は、上記サービス周期毎に順次一周期の特質に変化するように、上記サービス手段を制御するサービス制御手段
を備えたことを特徴とする。
【００４３】
ここで、上記「直ちに」は、発音指示を受けた直後であってももちろん良いが、一般にディジタル制御の場合、所定のクロックに同期した制御を行なう場合が多く、本発明においても、そのようなクロックに同期した時点まで待って上述の第１の発音制御を行なう場合も含まれ、上記「直ちに」は、その程度の幅を持つ用語として解釈される。ただし、このクロックの周期（発音の遅れ）は、発音開始の遅れが許容される、上述のサービス周期よりも短い周期（遅れ時間）である必要がある。
【００４４】
本発明の楽音生成装置によれば、発音指示を受けた場合には、直ちに、複数の楽音生成手段のうちのいずれかに対して、発音指示がなされた楽音を発音開始時の特質で生成開始するよう発音制御が行なわれる。また、本発明の楽音生成装置においては、楽音生成中の楽音生成手段について楽音の生成が開始された時点とは無関係に所定時間経過毎に生成中の楽音の特質が前回の発音制御から今回の発音制御までの経過時間に対応する時間後の特質に変化する。この時、楽音生成開始の発音制御がなされた時点から次の最初の発音制御までの時間はさまざまに変化することになるので、この時間を該所定時間の二分の一とみなすこととし、この最初の発音制御に関してはこの該所定時間の二分の一の時間に対応する分だけ楽音の特質を変化させるようにする。
【００４５】
該所定時間の二分の一の時間は、楽音生成開始の発音制御から次の最初の発音制御までの時間の平均値に等しいので、この最初の発音制御は従来に比べ高い精度で行なえることとなり、楽音生成開始時の楽音の特質の変化の劣化を防ぐことができる。
【００４６】
【発明の実施の形態】
以下、本発明の実施形態について説明する。
（実施形態１）
この実施形態１は、本発明の第１の楽音生成装置の一実施形態である。
【００４７】
この実施形態１では、モニタがサービスタスクを起動する間隔を、ボイスサービスの間隔より細かく設定する。しかし、サービスタスクは、起動される度に全てのボイスに対して処理をするのではなく、ボイスをスキャンしモニタにより通知されたスロット番号に応じたボイスのみを処理する。これにより、ＣＰＵの負荷を極端に増加させることなしに、初期発音とサービスの同期精度を高めることができる。
【００４８】
本実施形態でいうスロットとは、通常のサービスに必要な時間間隔をさらに短い時間に区分したものであり、一種の現在時刻を示す。本実施形態では、ボイスの実際のサービスの間隔を８ミリ秒、サービスタスク起動間隔（スロット時間）を１ミリ秒として、説明をする。
【００４９】
図１は、実施形態１における、モニタの構成を示すフローチャートである。
【００５０】
モニタ内ではタイマ割り込みは１ミリ秒の間隔で発生する。このときモニタは変数ｓｌｏｔを１だけ増加し、８の剰余（％８）を求めてｓｌｏｔに書き戻し（ステップ１＿１）、サービスタスクにイベントを発行する（ステップ１＿２）。つまり変数ｓｌｏｔは、１ミリ秒毎に、０，１，２，３，４，５，６，７，０，１，２，…のように繰り返す。なお、対象の数値の下位３ビットを取り出すことにより８の余剰を求めることができる。
【００５１】
ある時間における変数ｓｌｏｔの値を、その時点でのスロット番号と称することにする。
【００５２】
図２は、実施形態１における発音タスクの構成を示すフローチャートである。このフローチャート中の記号の意味は以下のとおりである。
【００５３】
（ａ）ｓｌｏｔ−ｖｏｉｃｅ＿１ｓｔ：スロット・ボイス・リストを示す。
【００５４】
このスロット・ボイス・リストは、各スロット毎にそのスロットで発音開始された発音中のボイスのボイス番号を発音開始順に示すリストである。このリストを記憶する領域として、表１に示すように、各スロット毎にボイス数＋１の大きさが確保されており、リスト全体では［スロット数＊（ボイス数＋１）］の大きさとなっている。
【００５５】
【表１】
0003636395.tif 000002
【００５６】
図２に示す、上から４つのステップ２＿１〜２＿４は、従来例（図１７参照）と同様である。
【００５７】
上から５つ目のステップ２＿５における、「現在のスロット番号を取得する」にあたっては、発音タスクがモニタ変数ｓｌｏｔを直接読んでもよいし、タスクからの書き込みを禁止するためにモニタ内に隠蔽し、取得のためにはタスクがモニタにシステムコールを発行しなくてはならないような仕様にしてもよい。
【００５８】
ステップ２＿６において、ｓｌｏｔ−ｖｏｉｃｅ＿１ｓｔ［ｐ＿ｓｌｏｔ］［ＥＮＤ］とあるのはスロット番号ｐ＿ｓｌｏｔのリストのボイス番号が格納されている領域の終端（ＥＮＤ）を意味している。
【００５９】
表１の例ではスロット０にボイス番号５，３，６，１が記憶されており（−１はいずれのボイス番号も記憶されていないことを意味する）、スロット１にはボイス番号２，８，４，９，１１，１６が記憶されている。ここでは、スロット０のリストにはボイス５，３，６，１がつながれている、というように表現することにする。
【００６０】
いま、さらにスロット０のタイミングでボイス１９の発音があった場合、ステップ２＿６ではこのリストを表２にように更新する。
【００６１】
【表２】
0003636395.tif 000003
【００６２】
つまり、スロット０のリストにボイス１９をつなげたことになる。上記フローチャートでは、簡単のため「スロット・ボイス・リストに追加する」という一言の表現で記述したが、実際にはこの部分は、図３に示すようなフローで表現される。
【００６３】
すなわち、図３に示すフローでは、そのスロットの終端をサーチし（ステップ３＿１〜３＿３）、その終端の部分にボイス番号をつなげ（ステップ３＿４）、さらにその次に、終端を意味する−１をつなげる（ステップ３＿５）。
【００６４】
あるいは、図３に示すフローの中の、ｉ＋１を計算するステップ３＿３で最大ボイス数との比較を行ない、ボイス数を越えた領域をアクセスすることがないようにすれば、スロット・ボイス・リストの大きさは  スロット数×ボイス数で足りることになる。全ボイスが１つのスロットに集中した場合、−１は必要ない。
【００６５】
図４は、サービスタスクの構成を示すフローチャートである。
【００６６】
表２の例で、現在のスロット番号を取得した結果（ステップ４＿１）、そのスロット番号が２だったなら、ボイス１０，０，１５，２２，１７についてサービスを行なうことになる（ステップ４＿２〜４＿７，４＿９）。すなわち、サービス間隔よりも短い間隔で起動されるサービスタスクにおいて、各ボイスをスキャンし、現タイミングでサービスするボイスを選択しそのボイスについてサービスを行なう。その際、例えばボイス１５がリリースステータスであって、なおかつレベル０であったら（ステップ４＿７）、サービスタスクは、表３に示すように、スロット２のスロット・ボイス・リストからボイス１５を削除する（ステップ４＿８）。
【００６７】
【表３】
0003636395.tif 000004
【００６８】
このフローを図５に示す。
【００６９】
図５に示すフローは、スロットＳにつながれているｉ番目のボイスを削除する場合に、それよりも後ろにつながれているボイスを、−１が現われるまで（ステップ５＿３）、順次１つずつ前に詰める（ステップ５＿１，５＿２，５＿４）ことを意味している。
【００７０】
尚、発音タスクのところで述べたように、ｓｌｏｔ−ｖｏｉｃｅ＿ｌｓｔを  スロット数×ボイス数  の大きさに節約したければ、ｊ＋１を計算する前に最大ボイス数との比較を行ない、ボイス数を越えている場合には終了するような判定を行なえばよい。
【００７１】
尚、実施形態中でサービスの時間カウンタは増加方向で計数したが、減少方向で計数してもよい。その場合、ｃｎｔ＿ｉｎｃをｃｏｕｎｔｅｒに足し算するのではなく、引き算することで実現できる。
【００７２】
以上のような処理を行なうことで、全てのボイスは８ミリ秒間隔でサービスされているにも関わらず、初期発音から初回サービスまでの時間は０〜１ミリ秒までの誤差に保てる。つまり初期発音から初回サービスまでの時間は７ミリ秒から８ミリ秒までの１ミリ秒の間に押え込むことが可能となる。
【００７３】
なお、前記実施形態ではサービスを行なうボイスをスロット毎に管理するようにしたので、あるスロットのタイミングにおいてサービスすべきボイスを知るのに全てのスロットのボイス管理情報を調べなくても該当するスロットのボイス管理情報のみを調べるだけでよく、処理が高速に行なえる。
【００７４】
尚、上記の説明では、説明の簡単のために、スロットとボイスとの関係を表１〜表３のような形式で記憶するようにしたが、この方法では多くの領域に無駄が生じる（上の表の…より右側の部分は意味を持たない）のと、ボイスリリース後にいくつものボイス番号をずらし込む必要があり低速になってしまうため、リンク構造にしてもかまわない。すなわち表３の例では、最大ボイス番号＝２９とすると、ｓｌｏｔ＿ｔｏｐ（各スロットの先頭のボイス番号）、ｓｌｏｔ＿ｅｎｄ（各スロットの終端のボイス番号）、ｓｌｏｔ＿ｎｅｘｔ（各ボイスの次のボイスのボイス番号）、およびｓｌｏｔ＿ｐｒｅｖ（各ボイスの前のボイスのボイス番号）は、それぞれ、表４，表５，表６，表７となる。
【００７５】
【表４】
0003636395.tif 000005
【００７６】
【表５】
0003636395.tif 000006
【００７７】
【表６】
0003636395.tif 000007
【００７８】
【表７】
0003636395.tif 000008
【００７９】
この場合、ｓｌｏｔ＿ｔｏｐ、ｓｌｏｔ＿ｅｎｄはそれぞれ８個のバッファ、ｓｌｏｔ＿ｎｅｘｔ、ｓｌｏｔ＿ｐｒｅｖはそれぞれボイス数と同じ数のバッファで収まるため、全体として（ボイス数×２＋スロット数×２）の領域で済む。またリリース時のボイス番号のずらし込みも、前後のボイスのつながりを書換えるだけなので高速である。
【００８０】
リンクの構造のしくみについては既に公知なので詳細は省略する。
【００８１】
尚、ここではモニタの制御によるマルチタスクで音源制御がなされていることが前提になっているが、実際のマルチタスクではタスク間の競合が発生するため、上記ｓｌｏｔ−ｖｏｉｃｅ＿ｌｓｔの書換えなどには保護機能を付加する必要がある。これについてもｓｅｍａｐｈｏｒｅなどの公知の技術を用いれば良い。
【００８２】
なお、上記の説明ではスロットとボイスとの関係を表１〜表７に示すような手法で管理するようにしたが、いずれのスロットでいずれのボイスのサービスを行なうかを管理できれば上記に示した以外の方法でも構わない。例えば上記実施形態では各スロット毎に対応するボイスを管理するようにしたが、逆にボイス毎に対応するスロットを管理するようにしてもよい。
【００８３】
また、上記実施形態では発音要求を受けた時にサービスタスクの起動タイミングとは非同期に初期発音処理を行なうようにしているが、初期発音処理を発音要求を受けた後の最初のサービスタスクの起動時に行なうようにし、以後は初期発音処理を行なったスロット毎にそのボイスに対するサービスを行なうようにしてもよい。この場合には初期発音から初回サービスまでの時間が正確に８ミリ秒となる。なおこの場合には発音要求から初期発音まで最大１ミリ秒かかることになるがこの程度の時間遅れは演奏上ほとんど問題とならない。
（実施形態２）
この実施形態２は、本発明の第１の楽音生成装置のもう１つの実施形態である。
【００８４】
この実施形態２では、サービスタスクを、ボイスの数に応じた数の複数のタスクによって構成する。発音タスクからのイベントでサービスタスクが生成される。以降、サービスタスクは従来通りタイマ・イベントにより起動され、ボイス終了時（音量エンベロープの全フェーズを実行した後）にサービスタスクが自分自身を終了させる。
【００８５】
サービスタスクは、自分自身を起動させるためのタイマ間隔を変更し、発音直後はサービス間隔を短くすることも可能である。これに関しては変形例として後述する。
【００８６】
ここでは、先ず、モニタの、サービスタスクに関するマルチタスク制御をつかさどるタスク管理ブロック（以後「ＴＣＢ」と略す）の説明をする。
【００８７】
図６は、タスク管理ブロック（ＴＣＢ）の構造図である。
【００８８】
各タスクにはタスク番号が順番にふられており、ＴＣＢは１個のタスクに１個ずつ設けられる。［  ］内はタスク番号を示す。尚、Ｎはタスク番号の最大値である。本実施形態では、各ボイス毎にサービスタスクを設けるので、タスク番号はそのタスクに対応するボイスのボイス番号と同じである。
【００８９】
「タスク状態フラグ」、「退避エリア」は一般のマルチタスクのプログラムにおいて使用されるものと同じであり、一方、「タイムアウト時刻」、「次のＴＣＢへのポインタ」、「前のＴＣＢへのポインタ」は本実施形態におけるサービスタスクに固有のものである。
【００９０】
「タスク状態フラグ」はタスクの状態を示すものであり、ＲＵＮ（実行権獲得）、ＲＥＡＤＹ（実行可能）、ＷＡＩＴ（イベント待ち）、ＤＯＲＭＡＮＴ（休止）などの状態が設定される。
【００９１】
「タスクを生成する」ということは、ＤＯＲＭＡＮＴ状態にあるタスクをＷＡＩＴ状態に遷移させることであり、「タスクを消滅させる」ということは、そのタスクをＤＯＲＭＡＮＴ状態に遷移させることである。ＷＡＩＴ状態のタスクは、待っている対象のイベントが発生した時にＲＥＡＤＹ状態にされる。尚、本発明によるサービスタスクにおいては、待っている対象のイベントは、所定時間の計時を行なうタイマによるイベントである。これらのタスク状態の遷移はモニタによって行なわれる。
【００９２】
モニタはＲＥＡＤＹ状態のタスク中から最も優先順位の高いタスクを一つだけ決定し、ＲＵＮ状態に遷移させ、そのタスクを起動し、実行させる。モニタの中のこのような処理を行なう部分を「スケジューラ」と呼ぶ。
【００９３】
ＴＣＢの退避エリアには、タスクの実行中断後の再開のために、そのタスクの前回の実行時のスタックポインタ、プログラムカウンタ、レジスタなどの内容が退避される。スケジューラは、起動されていたタスクの処理が中断された場合には、そのタスクのスタックポインタ、プログラムカウンタ、レジスタなどの内容をそのタスクの退避エリアに退避させ、その中断されたタスクを再起動する場合には、退避エリアから、退避されていたスタックポインタ、プログラムカウンタ、レジスタなどの内容を読み出して処理用のエリアに転送する。このような、起動するタスクの切換えを「ディスパッチ」と呼ぶ。
【００９４】
なお、スケジューラによってＲＵＮ状態に移行させるタスクとして選択されたタスクはモニタの処理終了後に直ちに実行される。
【００９５】
以上のタスク状態の遷移、スケジューラ、ディスパッチなどは公知なので詳細は省略する。
【００９６】
サービスタスクは所定の周期毎に起動されるものであり、「タイムアウト時刻」は、そのタスクが次に起動されるべき時刻を示している。「次のＴＣＢへのポインタ」、「前のＴＣＢへのポインタ」は、ＷＡＩＴ状態のタスクでのみ意味を持つものであり、ＷＡＩＴ状態のタスクの各サービスタスクが起動される時間的順番を示している。「次のＴＣＢへのポインタ」はそのタスクの次に起動されるタスクの番号を、「前のＴＣＢへのポインタ」はそのタスクの前に起動されるタスクの番号をそれぞれ示している。このように、各タスク間の時間順序（リンク状態）を示す２種類のポインタでつながれた一連のタスクを「タイマ・チェイン」と呼ぶ。従って、タイマ・チェインには、「タイムアウト時刻」の大きさに従った順番にＷＡＩＴ状態のタスクが並んでいる。
【００９７】
また、モニタには、図７に示すように、現在時刻を示す変数ＴＭ、タイマ・チェインにつながれているタスクのうち次に起動されるタスクを示すポインタＴＳＫ＿ＰＩＮＴＲが設けられている。
【００９８】
モニタは、所定周期毎（本実施形態では１ｍＳ毎）に発生されるタイマ割り込みに従って、図８に示す処理を行なう。
【００９９】
この図８に示すモニタ処理プログラム中の記号の意味は以下のとおりである。
【０１００】
（ａ）ｈｉｔ：起動されるべきタスクが存在するか否かを示している。
【０１０１】
ｈｉｔ＝１  ：  存在する
ｈｉｔ＝０  ：  存在しない
まず、現在時刻ＴＭを増加させ（ステップ８＿１）、次に起動すべきタスクの起動タイミングになったかどうかを判断する（ステップ８＿２）。尚、ＴＭを増加した結果がＴＭの最大値を越えた場合には、その値から最大値を減算した値に対応する値がＴＭの新たな値とされる。例えばＴＭの最大値を１２７、増加量を１として、ＴＭを０〜１２７の間で変化させるようにする。起動タイミングになっていればｈｉｔ＝１とし（ステップ８＿３）、そのタスクをタイマ・チェインから外す（ステップ８＿４）とともにＲＥＡＤＹ状態とし（ステップ８＿５）、その次のタスクに関して（ステップ８＿６）、同じ処理を行なう。
【０１０２】
起動すべきタスクが存在する場合には（ステップ８＿７）、ｈｉｔ＝０とした後（ステップ８＿８）スケジューラを起動し（ステップ８＿９）、存在しない場合には処理を終了する。その結果、その時刻で起動すべきタスクがＲＥＡＤＹ状態とされることになる。その後、スケジューラによって、ＲＥＡＤＹ状態のタスクが優先順位に従って起動される。
【０１０３】
すなわち、サービス間隔よりも短い間隔で実行されるモニタにおいて、各ボイスに対応するサービスタスクをスキャンし、現タイミングで起動するサービスタスクを選択しそのタスクを起動する。
【０１０４】
ここに示したように、タイマによる割込み処理において、そのタイミングにおいて起動すべきサービスタスクを知るのに全てのサービスタスクを調べなくても、チェインの先頭のサービスタスクのみを調べるだけでよいので処理が高速に行なえる。
【０１０５】
起動していたタスクが一通りの処理を終えた時には、モニタに対してモニタコールを行なう。サービスタスクからのモニタコールには、そのタスクがＷＡＩＴ状態に移行する時の「ＷＡＩＴコール」、そのタスクがＤＯＲＭＡＮＴ状態に移行する時の「ＤＯＲＭＡＮＴコール」の２種類がある。
【０１０６】
サービスタスクからこれらのモニタコールが行なわれる時にはコールしたタスクのタスク番号（すなわちボイス番号）をモニタに知らせる。これらのモニタコールに対してモニタは以下の処理を行なう。
【０１０７】
図９は、ＷＡＩＴコールに対するモニタの処理を表わしたフローチャートである。
【０１０８】
尚、図９に示すフローチャート中の記号の意味は以下のとおりである。
【０１０９】
（ａ）ｓｒｖ＿ｉｎｔｅｒｖａｌ：サービスタスクの起動周期を示す定数である。
【０１１０】
このフローでは、そのタスクの状態がＷＡＩＴ状態に変更され（ステップ９＿１）、そのタスクが次に起動される時刻が設定され（ステップ９＿２）、そのタスクがタイムアウト時刻に応じてタイマー・チェインに挿入され（ステップ９＿３）、スケジューラが起動される（ステップ９＿４）。
【０１１１】
図９に示すフローチャート中、ＴＭ＿ＯＵＴは、ＴＭ同様、増加した結果がＴＭ＿ＯＵＴの最大値（ＴＭの最大値と同じ）を越えた場合には、その値から最大値を減算した値に対応する値が新たな値とされる。前述のように、本実施形態ではタイマ割り込みの間隔を１ｍＳとしたので、ｓｒｖ＿ｉｎｔｅｒｖａｌを８とした場合にはＴＭ＿ＯＵＴはサービスの度に８づつ増加し、８ｍＳ毎にサービスが行なわれることとなる。尚、ＴＭ、ＴＭ＿ＯＵＴをともに０〜７の整数とした場合には、ＴＭ＿ＯＵＴは、後述する発音時に設定される一定値で構わないため、ステップ９＿２の処理は不要となる。
【０１１２】
また、ステップ９＿３でタイマ・チェインに挿入するにあたっては、タイマ・チェインを辿り、前のタスクのＴＭ＿ＯＵＴがそのタスクのＴＭ＿ＯＵＴ以下であって、後のタスクのＴＭ＿ＯＵＴがそのタスクのＴＭ＿ＯＵＴよりも大きい場所を探し、前後のタスクおよびそのタスクのＮＥＸＴ＿ＴＳＫおよびＰＲＥＶ＿ＴＳＫを書き換えることにより、そのタスクをその場所に挿入する。
【０１１３】
図１０は、ＤＯＲＭＡＮＴコールに対するモニタの処理を表わしたフローチャートである。
【０１１４】
図１０に示すフローでは、そのタスクの状態がＤＯＲＭＡＮＴ状態に変更されて（ステップ１０＿１）、スケジューラが起動される（ステップ１０＿２）。
【０１１５】
前述の様に、ＷＡＩＴ状態のタスクは時間経過に伴って起動され、ＤＯＲＭＡＮＴ状態とされたタスクは時間経過にかかわらず起動されなくなる。
【０１１６】
図１１は、発音タスクのフローチャートである。
【０１１７】
ステップ１１＿１〜１１＿４は、従来技術（図１７参照）と同様であり、最後の処理（ステップ１１＿５）およびモニタコール内容のみが従来と異なる。
【０１１８】
ステップ１１＿５に示すように、タイムアウト時刻ＴＭ＿ＯＵＴは発音タスクの起動時の時刻ＴＭの値で初期化される。
【０１１９】
また、従来技術ではサービスタスクは全ボイスに共通であったが、本実施形態では各ボイス毎にサービスタスクを設けるようにしたため、発音タスクからモニタに対して発音したボイスのサービスタスクを生成するように依頼する（ＴＡＳＫ  ＧＥＮＥＲＡＴＥコール）。モニタは、これに応じて、図９に示したＷＡＩＴコール対する処理と類似の処理を行なう。具体的には、発音タスクを発音イベント待ち状態に遷移させるとともに、依頼されたボイスのサービスタスクをＷＡＩＴ状態に遷移させ（ステップ９＿１と同様）、そのサービスタスクのタイムアウト時刻を設定し（ステップ９＿２と同様）、そのサービスタスクのタイムアウト時刻に応じてそのサービスタスクをタイマー・チェインに挿入し（ステップ９＿３と同様）、そのサービスタスクの退避エリアを初期化し、スケジューラを起動する（ステップ９＿４と同様）。タイムアウト時刻ＴＭ＿ＯＵＴは発音タスク起動時の時刻ＴＭの値にサービスタスクの起動周期ｓｒｖ＿ｉｎｔｅｒｖａｌが加算された値となるので、次回にそのボイスのサービスタスクが起動されるのはサービスタスクの起動周期ｓｒｖ＿ｉｎｔｅｒｖａｌ分の時間が経過した後となる。なお、ＴＭ、ＴＭ＿ＯＵＴをもとに０〜７の範囲内の整数とした場合には、この処理は
ＴＭ＿ＯＵＴ＝ＴＭ
とするだけで構わない。退避エリアの初期化は、レジスタの内容を所定の値とし、プログラムカウンタの内容をそのサービスタスクのプログラムの先頭位置とし、さらにこれらのレジスタおよびプログラムカウンタをスタックにプッシュしそれに応じてスタックポインタの値を設定することにより行なう。
【０１２０】
図１２は、サービスタスクのフローチャートである。
【０１２１】
ｃｏｕｎｔｅｒ［ｖｏｉｃｅ］を更新し（ステップ１２＿１）、前回のサービスから所定時間経過後の音高、音質、音量を求め（ステップ１２＿２）、ボイスに供給し（ステップ１２＿３）、発音中の場合には（ステップ１２＿４）モニタからのタイマ・イベント待ち状態となる点に関しては、従来技術と本質的に同じであるが、本実施形態では各ボイス毎にサービスタスクを設けるようにしたため、発音が終了したら（ステップ１２＿４）そのボイスのサービスタスクをＤＯＲＭＡＮＴ状態とするようモニタに依頼する点が異なる。モニタはこのＤＯＲＭＡＮＴコールに対して前述の処理を行ない、そのボイスのサービスタスクをＤＯＲＭＡＮＴ状態に遷移させる。ＤＯＲＭＡＮＴ状態のボイスは、以後、新たに発音が割り当てられ、ＷＡＩＴ状態に遷移されるまではサービスタスクが起動されないようになる。このため、処理する必要のないサービスが起動されることがなくなりＣＰＵの負荷が不必要に重くなるのを防ぐことができる。
【０１２２】
この手法を使うと、初期発音と初回サービスとの間隔が正確に保てるようになる。例えば、タイマからの割り込みの時間間隔を１ミリ秒、ｓｒｖ＿ｉｎｔｅｒｖａｌを８ミリ秒と設定したとすると、初期発音と初回サービスとの間隔は７ミリ秒ないし８ミリ秒となり、最大でも１ミリ秒以内の誤差で起動される。
【０１２３】
尚、本実施形態ではボイスの発音が終了した場合に、そのボイスのサービスタスクをＤＯＲＭＡＮＴ状態とすることにより起動しないようにしたが、別の手法を用いるようにしてもよい。例えば、各タスク毎にそのタスクが待っている（ＷＡＩＴ）対象のイベントを設定し、スケジューラは優先順位に従いタスクをスキャンし、個々のタスクがどのようなイベントを待って（ＷＡＩＴ）いるか、どのようなイベントが発生しているかを調べ、あるタスクの待っているイベントと発生しているイベントが合致した場合に、そのタスクを起動するするようにしてもよい。尚、この場合には、発音が終了したボイスのサービスタスクに関しては、タイマによるイベントを待つ対象から外すように設定すればよい。
【０１２４】
なお、上記の説明では各サービスタスクが起動されるタイミングを図６に示す各サービスタスク毎に設定したタイムアウト時刻およびタイマ・チェインによって管理するようにしたが、いずれのタイミングでいずれのサービスタスクを起動するかが管理できれば上記に示した以外の方法でも構わない。例えば、実施形態１で示したものと同様に、各タイミング毎に起動すべきサービスタスクをリスト化して管理するようにしてもよい。あるいはタイムアウト時刻の代りに実施形態１で示したものと同様に各スロット毎に起動すべきサービスタスクをリスト化して管理するようにしてもよい。
（実施形態２の変形例）
ところで、上述の実施形態２では、サービスタスクの起動周期は一定としたが、発音直後はより短い周期で発音タスクを起動するようにしてもよい。
【０１２５】
短い時間周期で木目細かくサービスを行なった方が楽音の品質が向上するが、ＣＰＵの負荷が重くなり現実には困難である。しかし、以下の点に着目して、発音直後の、楽音の品質に特に影響のある部分に関してのみサービスの周期を短くすることにより、ＣＰＵの負荷をほとんど重くせずに楽音の品質を大きく向上させることが可能となる。
【０１２６】
（１）木目細かなサービスが必要となるのは楽音の特質の変化が激しい部分である。
【０１２７】
（２）楽音のアタック部分は楽音の特質の変化が激しい。
【０１２８】
（３）楽音のアタック部分は楽音の特色を特に強く印象付ける部分である。
【０１２９】
（４）楽音のアタック部分は短時間である。サービス周期を短くすることによってＣＰＵの負荷が増すことになり他のボイスに対するサービスの遅延が生じるおそれがあるが、アタック部分は短時間であるため負荷の増加期間が短く他のボイスに対するサービスへの影響が小さい。
【０１３０】
以下その処理例を示す。
【０１３１】
図１３は、発音タスクのフローチャートである。
【０１３２】
この図１３のフローチャート中の記号の意味は、以下のとおりである。
【０１３３】
（ａ）ａｔａｃｋ＿ｃｏｕｎｔｅｒ［ｖｏｉｃｅ］：そのｖｏｉｃｅの発音後一定時間経過を認知するためのカウンタである。
【０１３４】
（ｂ）ｓｒｖ＿ｉｎｔｅｒｖａｌ［ｖｏｉｃｅ］：そのｖｏｉｃｅのサービスタスクの起動周期を示す変数である。
【０１３５】
（ｃ）ｓｒｖ＿ｉｎｔ＿ｓｔｄ：サービスタスクの標準起動周期を示す定数である。これは前記実施形態２のｓｒｖ＿ｉｎｔｅｒｖａｌと同じ値である。
【０１３６】
ステップ１３＿１〜１３＿４は、前記の実施形態２と同様であり、前記の実施形態２と異なるのは、発音後一定時間を認知するためのカウンタをボイス毎に設け０で初期化する処理（ステップ１３＿５）を追加した点と、サービスタスクが起動されるまでの時間を８分の１に短くした（ステップ１３＿６）点である。具体的には、前記実施形態２のｓｒｖ＿ｉｎｔｅｒｖａｌと同じ値の、サービスタスクの標準起動周期を示す定数ｓｒｖ＿ｉｎｔ＿ｓｔｄを設け、前記実施形態２で定数としたｓｒｖ＿ｉｎｔｅｒｖａｌをボイス毎に設けて変数とし、発音タスクにおいてｓｒｖ＿ｉｎｔ＿ｓｔｄの８分の１で初期化している。尚、モニタでは、ＷＡＩＴコール、ＴＡＳＫ  ＧＥＮＥＲＡＴＥコールに対応して、そのボイスに対応するｓｒｖ＿ｉｎｔｅｒｖａｌ［ｖｏｉｃｅ］を用いてそのタスクの次の起動時刻を設定する。従って、ボイス毎にサービスタスクの起動周期が異なるようになる。
【０１３７】
このため前記の実施形態２では発音タスクが起動してから８ｍＳ（正確には７〜８ｍＳ）後にサービスタスクが起動されたが、本実施形態では１ｍＳ（正確には０〜１ｍＳ）後にサービスタスクが起動される。
【０１３８】
図１４は、サービスタスクのフローチャートである。
【０１３９】
この図１４のフローチャート中の変数の意味は、以下のとおりである。
【０１４０】
（ａ）ＭＡＸ＿ＩＴＶＬ：発音後細かくサービスをする期間を意味する定数である。
【０１４１】
ｓｒｖ＿ｉｎｔｅｒｖａｌは発音タスクでサービスタスクの標準起動周期の８分の１とされているので、発音後一定時間はサービス周期は標準の８分の１となる。一定時間を計るのがａｔａｃｋ＿ｃｏｕｎｔｅｒであり、ＭＡＸ＿ＩＴＶＬ回サービスが行なわれるまでは（ステップ１４＿１）サービス周期を標準の８分の１に保ち（ステップ１４＿２〜１４＿３）、それを過ぎたら標準に戻す（ステップ１４＿４〜１４＿５）。このため例えばサービスタスクの標準起動周期が８ｍＳに設定されている場合には、発音直後の一定時間のみサービスタスクの起動周期は１ｍＳとされる。尚、ＭＡＸ＿ＩＴＶＬは楽音の特質の変化が激しい期間に対応して決めればよく、例えば２０ｍＳに対応する値とする。すなわち、発音直後に１ｍＳでサービスタスクが起動される場合には例えば２０とする。
【０１４２】
図１４に示すフローにおけるステップ１４＿６〜１４＿８は、前述した実施形態２のフロー（図１２のステップ１２＿２〜１２＿４）と同様である。
【０１４３】
尚、ここでは全てのボイス（サービスタスク）が同一優先順位であるかのように説明したが、ｓｒｖ＿ｉｎｔｅｒｖａｌの値が小さいボイスを優先的に処理するようにすれば、複数のボイスが発音中でＣＰＵ負荷が大きい場合においても、より精密なアタックが再現できる。そのためには、例えば、モニタのＷＡＩＴコールに対応してサービスタスクをタイマ・チェインに挿入する処理において、挿入しようとするタスクのＴＭ＿ＯＵＴと同じ値のＴＭ＿ＯＵＴのタスクが既にタイマ・チェインにつながれている場合に、それらのタスクのｓｒｖ＿ｉｎｔｅｒｖａｌを比較し、小さい方のタスクが前になるように挿入すればよい。
【０１４４】
また、この実施形態ではサービス間隔を１ミリ秒もしくは８ミリ秒と２段階に設定したが、ａｔａｃｋ＿ｃｏｕｎｔｅｒあるいはｃｏｕｎｔｅｒを段階的に判断し、その中間値やもっと長い間隔など、細かく変化するようにしてもかまわない。
【０１４５】
なお、この実施例では発音直後の部分に対してサービス間隔を短くしたが、これ以外の場合にも楽音の特質の変化が激しい部分等に関してサービス間隔を短くするようにしてもよい。また、逆に楽音の特質の変化があまりない部分等に関してサービス間隔を標準サービス間隔よりも長くしてもよい。この場合には楽音の品質にあまり影響を与えることなくサービス全体に対する負荷を低減させることが可能となる。
【０１４６】
なお、前記実施例１、２では各ボイスに対するサービスタイミングを管理するのにあたって、時間経過後に従って変化する時間スロット毎にボイスを管理したり（実施例１）、時間経過に従って変化する時刻に対応してボイス毎に次にサービスされる時刻を管理したり（実施例２）といった方法を使用したが、各ボイスに対するサービスタイミングが管理できれば別の方法を使用してもよい。
【０１４７】
例えば、ボイス毎に次にサービスされるまでの待ち時間を管理するようにし、サービスを行なう度に待ち時間をサービス周期に対応する値に初期化し所定時間毎に各ボイスの待ち時間を減少させ待ち時間が０になった場合にはそのボイスに対するサービスを行なうようにしたり、あるいは、ボイス毎に前回のサービスからの経過時間を管理するようにし、サービスを行なう度に経過時間を０に初期化し所定時間毎に各ボイスの経過時間を増加させ経過時間がサービス周期に対応する値になった場合にはそのボイスに対するサービスを行なうようにしてもよい。あるいは、次にサービスされるまでの待ち時間毎に対応するボイスを管理するようにし、サービスを行なう度にそのボイスをサービス周期に対応する待ち時間に登録し所定時間毎に各待ち時間を減少させ待ち時間が０になった場合にはその待ち時間に登録されていたボイスに対してサービスを行なうようにしたり、あるいは、前回のサービスからの経過時間毎に対応するボイスを管理するようにし、サービスを行なう度にそのボイスを０の経過時間に登録し所定時間毎に各経過時間を増加させ経過時間がサービス周期に対応する値になった場合にはその経過時間に登録されていたボイスに対してサービスを行なうようにしてもよい。
【０１４８】
あるいは、自動演奏装置における自動演奏データのタイミング管理記憶方法と同様に、ボイスのサービスされる順番及びボイス毎に前のボイスのサービスからそのボイスのサービスまでの時間間隔あるいはそのボイスのサービスから次のボイスのサービスまでの時間間隔を管理するようにし、自動演奏データの読み出し処理と同様に、これらのサービス管理情報を時間経過に従って読み出すようにしてもよい。この場合、ボイスの順番を管理するには実施例１で示したようなリンク構造とすればよい。またこの場合、発音要求に応じて新たにサービスするボイスが出現した場合あるいは発音終了に応じてサービスを取止めるボイスが出頭した場合にはそれに応じてボイスの順番および時間間隔を書換えるようにする。
【０１４９】
あるいは、前記実施例１、２ではタイマ割込みを行なうタイマを全ボイス共通に１つだけ設けるようにしたが、各ボイス毎にサービス周期を計測するタイマを設け、各タイマのタイマ割込みに応じて対応するボイスに対してサービスを行なうようにしてもよい。この場合、初期発音の処理時に次のタイマ割込みがサービス周期に対応する時間後にかかるようにそのタイマを初期かするようにする。あるいは実施例１と同様に各スロット毎にサービス周期を計測するタイマを設け、各タイマのタイマ割込みに応じてそのスロットに対応するボイスに対してサービスを行なうとともにサービス周期後に次のタイマ割込みがかかるようにそのタイマ初期化するようにしてもよい。
【０１５０】
さらに実施例１、２、これらを変形させた方法、および上記の方法を適宜組合せるようにしてもよい。実施例１、２を組合せた方法として例えば以下のようにしてもよい。実施例２に示したように各ボイス毎にサービスタスクを設け、各サービスタスクの起動タイミングの管理方法を実施例１に示した方法とする。すなわち時間を複数のスロットに分割し各スロット毎にそのスロットのタイミングにおいて起動すべきサービスタスクを登録し、各スロットタイミング毎にスロット番号に基づいてそのスロットに登録されているサービスタスクを起動するようにする。この場合、サービス周期を一定とし一サービス周期でスロットが一巡するようにスロット数を決めた場合にはスロットへのサービスタスクの登録は実施例１に示したように初期発音の処理時にのみ行なえばよい。また、実施例２に示したようにサービスタスクの標準起動周期よりも短い間隔でサービスタスクを起動させたい場合には、サービ毎にサービスタスクを次に起動すべきタイミングに対応するスロットへ登録するようにすればよい。さらにサービス周期をスロットの一巡する周期よりも長くしたい場合にはサービス毎にそのサービスタスクを次に起動すべきタイミングに対応するスロットへ登録するとともに、実施例２に示したようにサービスタスク毎に次に起動されるべき時刻を登録するようにすればよい。
【０１５１】
この場合、具体的には次のようにすればよい。モニタで現在時刻ＴＭを１ｍＳ毎に１づつ増やし０〜１２７の間で変化するようにし、この現在時刻ＴＭの下位３ビットの値を現在スロットとする。従ってスロットは０〜７で変化する。実施例２に示した処理方法で各サービスタスク毎に次回のサービス時刻を示すタイムアウト時刻ＴＭ＿ＯＵＴを求めＴＣＢに記憶しておくとともに、サービス時刻ＴＭ＿ＯＵＴの下位３ビットに対応するスロットにそのサービスタスクを登録する。モニタは１ｍＳ毎に現在スロットに対応して登録されているサービスタスクのうち現在時刻ＴＭと一致するタイムアウト時刻ＴＭ＿ＯＵＴのサービスタスクをＲＥＡＤＹ状態とする。
【０１５２】
このようにすれば、現在スロットに対応して登録されているサービスタスクのみを検索するだけで現在時刻で起動すべきサービスタスクを見つけることができるので処理が高速に行なえるのみならず、サービスタスクを登録すべきスロットを見つける処理も高速に行なえ、さらにスロットへの登録処理も高速に行なえる。また、このようにすれば実施例２で示したように標準サービス周期よりも短い１ｍＳなどのサービス周期が実現でき、さらに標準サービス周期よりも長い１６ｍＳや２４ｍＳなどのサービス周期も実現できる。
【０１５３】
なお、この場合、スロットへのサービスタスクの登録方法を１で示したようなリンク構造とした場合、サービスタスクを実施例１で示したように発音開始順に並べてもよいし、実施例２で示したようにタイムアウト時刻の順に並べてもよい。前者の場合には、起動すべきサービスタスクを見つける場合にそのスロットに登録されている全てのサービスタスクをチェックする必要があるがサービスタスクをつなげるリンク上の位置が決まっているのでサービスタスクを登録する処理が高速に行なうことができる。後者の場合には、サービスタスクをつなげるリンク上の位置を探す処理が必要となるが、起動すべきサービスタスクを見つける場合にはリンクの先頭をチェックするだけでよいので処理が高速に行なえる。
（実施例３）
この実施例３は、本発明の第２の楽音生成装置の一実施例である。
【０１５４】
この実施例３では、前述の実施例１，２とは異なり、初期発音が終了してから初回サービスが起動されるまでの時間を計測し、楽音の特質パラメータの変化のための時間情報に反映させる。すなわち実施例１，２が初期発音が終了してから初回サービスが起動されるまでの時間がなるべく一定となるようにして、その一定時間に応じた楽音の特質パラメータを求めるようにしていたのに対して、実施例３では、従来の技術と同様に、初期発音が終了してから初回サービスが起動されるまでの時間が変動するのを許し、その代りにその時間を計測し、計測された時間に応じた楽音の特質パラメータを求めるようにする。
【０１５５】
一般にサービスタスクが定期的にボイスサービスを行なう場合、各ボイスには必ず経過時間を示す時間情報が存在し、その時間情報に基づき楽音の特質の時間変化を求める。通常、ボイスサービスを行なう度にこの時間情報を一定量増加させることで時間管理を行なう。
【０１５６】
実施例３では発音タスクが発音を終えた時、サービスタスク起動用のタイマを読み、サービス起動間隔中のどの時点で発音が行なわれたかを示す情報を得る。この値を発音ボイスに対応したバッファにストアすることで、サービスタスクは、経過時間を、０からではなく実際に初期発音が終了してから初回サービスが起動されるまでの時間からスタートさせる。
【０１５７】
ここでは、一例として、ボイスサービスの間隔を８ミリ秒とする。この場合、初期発音と初回サービスの実間隔は０〜８ミリ秒の間で不定である。
【０１５８】
一般に、ＣＰＵのタイマ・インタラプトを用いる場合、比較レジスタに値を設定し、タイマ・カウンタをクロックによってカウントアップさせ、比較レジスタと値が等しくなった時点で割り込みがかかり、その時点でタイマ・カウンタをクリアするような処理を繰り返し行なう。
【０１５９】
いま比較レジスタの設定値をＴｓとすると、サービスを８ミリ秒で起動させるにはタイマ・カウンタを０からカウントアップしてＴｓに至るまでの時間が８ミリ秒になるよう、クロック周波数とＴｓを設定しておけば良いことになる。
【０１６０】
ここで、任意の時間におけるタイマ・カウンタの値Ｔｃは、０〜Ｔｓ内にあることになるが、
Ｔｃ／Ｔｓ
を求めると、その値は８ミリ秒というサービス間隔内のどの時点（割合）に存在しているかという意味になる。ここでｃｎｔ＿ｉｎｃをサービスタスクの起動周期に対応する時間経過を示す定数とすると、
Ｔｃ／Ｔｓ＊ｃｎｔ＿ｉｎｃ
は前回のタイマ・インタラプトからの経過時間すなわち前回のサービスタイミングからの時間経過を示していることになる。従って、発音タスク起動時のタイマ・カウンタの値Ｔｃに基づいて上記の値を負にした
−Ｔｃ／Ｔｓ＊ｃｎｔ＿ｉｎｃ
で、初期発音以降の経過時間を表現する変数ｃｏｕｎｔｅｒを初期化すれば、サービスタスクにおいて、初期発音以降の経過時間を表現する変数ｃｏｕｎｔｅｒの値がサービスタスクの起動周期に対応する時間経過を示す定数ｃｎｔ＿ｉｎｃの分だけ増加された後に、その変数ｃｏｕｎｔｅｒに基づいてサービスが行なわれるので、初期発音の後の初回のサービスの時にはｃｏｕｎｔｅｒ＝（Ｔｓ−Ｔｃ）／Ｔｓ＊ｃｎｔ＿ｉｎｃとなり、初期発音が終了してから初回サービスが起動されるまでの実際の経過時間に基づいて特質パラメータ（エンベロープ、ＬＦＯなど）を求めることができる。
【０１６１】
図１５は、発音タスクのフローチャートである。このフローチャート中、ステップ１５＿１〜１５＿３、１５＿５は従来と同じであり、図７のステップ１７＿１〜１７＿３、１７＿５にそれぞれ対応している。
【０１６２】
上述の理由により、発音タスクでは、発音処理に伴い、−Ｔｃ／Ｔｓ＊ｃｎｔ＿ｉｎｃを、発音ボイスに応じた初期発音からの経過時間を示すバッファｃｏｕｎｔｅｒ［ｖｏｉｃｅ］に記憶する（ステップ１５＿４）。
【０１６３】
尚、サービスタスクは従来技術と同じ処理を行なう（図１８参照）。
【０１６４】
これにより、初期発音とサービスの同期をとらなくても、従来よりもはるかにいびつさのないエンベロープが形成できる。
【０１６５】
尚、初期発音が終了してから初回サービスが起動されるまでの実際の経過時間に基づいてｃｏｕｎｔｅｒの値が補正されれば、上記実施例３の方法に限らず、他の処理方法をとってもよい。例えば、上述した実施例３ではサービスタスクでは経過時間パラメータｃｏｕｎｔｅｒを増加させた後に特質パラメータを求めているが、特質パラメータを求めた後に経過時間パラメータｃｏｕｎｔｅｒを増加させる場合には、発音タスクでは経過時間パラメータを（Ｔｓ−Ｔｃ）／Ｔｓ＊ｃｎｔ＿ｉｎｃで初期化すればよい。あるいは発音タスクでは経過時間パラメータｃｏｕｎｔｅｒを０で初期化し初回のサービスタスクのみ経過時間パラメータｃｏｕｎｔｅｒを（Ｔｓ−Ｔｃ）／Ｔｓ＊ｃｎｔ＿ｉｎｃだけ増加させてもよい。この場合はサービスタスクが初回サービスであることを認識する為の手段が必要となる。このため発音タスクは、初期発音を終了させると発音完了を示すフラグをセットするようにし、サービスタスクはこのフラグが立っていたらそのサービスはそのボイスにとって第１回目のサービスであると考え、時間管理のカウンタｃｏｕｎｔｅｒに対し（Ｔｓ−Ｔｃ）／Ｔｓ＊ｃｎｔ＿ｉｎｃを加算しそのフラグをリセットするようにすればよい。
（実施例４）
この実施例４は、本発明の第３の楽音生成装置の一実施例である。
【０１６６】
この実施例４では、実施例３と同様に初期発音が終了してから初回のサービスが起動されるまでの時間が変動するのを許し、その代りに初回のサービスはサービスタスク起動周期の半分の時間に基づいて特質パラメータ（音量、音質、音高など）を求める。すなわち、初回のサービスでは通常の半分だけ楽音の特質を変化させる。サービス起動周期の半分の時間というのは非同期で動いている発音タスクとサービスタスクの時間間隔の平均値に等しい。そのため自然なエンベロープ、ＬＦＯを描く可能性が最も高くなる。
【０１６７】
すなわち、前記実施例３では、発音タスクから初回のサービスタスクまでの実際の経過時間に基づく特質パラメータを求めたのに対し、本実施例４では発音タスクから初回のサービスタスクまでの平均経過時間に基づいて特質パラメータを求める、ということである。
【０１６８】
図１６は、発音タスクのフローチャートである。
【０１６９】
ここでは、発音タスクで経過時間パラメータｃｏｕｎｔｅｒをサービスタスク起動周期を示す定数ｃｎｔ＿ｉｎｃの−１／２で初期化し（ステップ１６＿４）、サービスタスクでは経過パラメータｃｏｕｎｔｅｒを起動周期ｃｎｔ＿ｉｎｃの分だけ増加させた後に特質パラメータを求める。
【０１７０】
尚、サービスタスクは従来技術と同じ処理を行なう（図１８参照）。
【０１７１】
これにより、初期発音とサービスの同期をとらなくても、従来よりもはるかに高い頻度でいびつさのないエンベロープが形成できる。
【０１７２】
尚、発音タスクから初回のサービスタスクまでの平均経過時間に基づいてｃｏｕｎｔｅｒの値が補正されれば他の処理方法をとってもよく、実施例３で説明したのと同じバリエーションが使える。
【０１７３】
また、上記実施例１〜４では、サービスタスクにおいて、初期発音からの経過時間あるいは現フェーズ開始時からの経過時間を示すｃｏｕｎｔｅｒに基づいて新たな特質パラメータ（エンベロープ、ＬＦＯなどの値）を求めているが、特質パラメータを時間経過に従ってサービス毎に変化させることができれば他の処理方法を用いてもよい。例えばその時点の特質パラメータの変化速度に応じてサービス周期に対応する時間経過毎の特質パラメータの変化量を求め、この分だけ前回のサービス時の特質パラメータを変化させる処理によって新たな特質パラメータを求めるようにしてもよい。すなわち、前回のサービス時の特質パラメータをＬ＿ｏｌｄ、今回のサービス時の特質パラメータをＬ＿ｎｅｗ、サービス周期に対応する時間経過毎の特質パラメータの変化量をＬ＿ｉｎｃとして、
Ｌ＿ｎｅｗ＝Ｌ＿ｏｌｄ＋Ｌ＿ｉｎｃ
を各サービス毎に行なうようにする。
【０１７４】
この場合、実施例３では上記式の処理を各サービス毎に行なうようにするが、初期発音後の初回サービスのみは結果的に
Ｌ＿ｎｅｗ＝Ｌ＿ｏｌｄ＋Ｌ＿ｉｎｃ＊（Ｔｓ−Ｔｃ）／Ｔｓ
が行なわれるようにする。実施例４では同様に初期発音後の初回サービスのみは結果的に
Ｌ＿ｎｅｗ＝Ｌ＿ｏｌｄ＋Ｌ＿ｉｎｃ／２
が行なわれるようにする。
【０１７５】
尚、上述のいずれの実施例１〜４も、発音要求直後の処理に関して説明したが、消音要求（ノート・オフ）直後に関しても同様の処理を施すようにしてもよい。これによりノート・オン直後だけではなくノート・オフ直後のエンベロープ変化についても同様に正確に再現可能である。
【０１７６】
【発明の効果】
以上説明したように、本発明によれば、従来と比べ、楽音生成開始時の楽音の特質の変化の劣化を防ぐことができる。
【図面の簡単な説明】
【図１】  実施例１における、モニタの構成を示すフローチャートである。
【図２】  実施例１における発音タスクの構成を示すフローチャートである。
【図３】  図２に示す発音タスクの部分フローを示す図である。
【図４】  実施例１における、サービスタスクの構成を示すフローチャートである。
【図５】  図４に示すサービスタンクの部分フローを示す図である。
【図６】  タスク管理ブロック（ＴＣＢ）の構造図である。
【図７】  モニタで用いられるレジスタの名称を示した図である。
【図８】  モニタ処理プログラムのフローチャートである。
【図９】  ＷＡＩＴコールに対するモニタの処理を表わしたフローチャートである。
【図１０】  ＤＯＲＭＡＮＴコールに対するモニタの処理を表わしたフローチャートである。
【図１１】  発音タスクのフローチャートである。
【図１２】  サービスタスクのフローチャートである。
【図１３】  発音タスクのフローチャートである。
【図１４】  サービスタスクのフローチャートである。
【図１５】  発音タスクのフローチャートである。
【図１６】  発音タスクのフローチャートである。
【図１７】  従来の発音タスクを示すフローチャートである。
【図１８】  従来のサービスタスクのフローチャートである。
【図１９】  エンベロープの変化の一例を示す模式図である。
【図２０】  エンベロープによって制御される楽音の特質の、想定された変化状態を示す図である。
【図２１】  初期発音のタイミングとサービスの起動タイミングとの関係の一例を示す図である。
【図２２】  エンベロープによって制御される楽音の特質の、実際の変化状態の一例を示す図である。
【図１】
0003636395.tif 000009
【図２】
0003636395.tif 000010
【図３】
0003636395.tif 000011
【図４】
0003636395.tif 000012
【図５】
0003636395.tif 000013
【図６】
0003636395.tif 000014
【図７】
0003636395.tif 000015
【図８】
0003636395.tif 000016
【図９】
0003636395.tif 000017
【図１０】
0003636395.tif 000018
【図１１】
0003636395.tif 000019
【図１２】
0003636395.tif 000020
【図１３】
0003636395.tif 000021
【図１４】
0003636395.tif 000022
【図１５】
0003636395.tif 000023
【図１６】
0003636395.tif 000024
【図１７】
0003636395.tif 000025
【図１８】
0003636395.tif 000026
【図１９】
0003636395.tif 000027
【図２０】
0003636395.tif 000028
【図２１】
0003636395.tif 000029
【図２２】
0003636395.tif 000030