新規音源ドライバのページ
last updated 2008.06.08
2002.08.11 : このページの趣旨
前々から構想だけはあった新規音源ドライバの企画、設計について記載したいと思います。
オブジェクト指向、UMLを勉強しながら作っていますので、分析/図が間違っている可能性も高いです。その際は指摘していただけると幸いです。
#音源ドライバの名前募集中(笑)
2002.08.11 : はじめに
WinFMP / PMDWin を公開して非常に多くの人に使っていただきましたが、新しい曲を作って下さる方はそれほど多くはありませんでした。
Windows ベースの開発環境が整っていなかった事が一番の原因でしょうが、長年の探求の結果 OPNA の限界まで使いこなされていて「新しい音」を作ることが難しく、パート数等の制限もあったためではないかと思います。
また、WinFMP / PMDWin はそれぞれ5種類もの音源をサポートしていて、データ作成時はもとより、音源ドライバやパラメータービューアー等のプログラムでも似たようなコードを5種類書く必要があり煩雑でした。
今までの制約を打ち破るために、今回新たに従来よりシンプルな構造で表現力、拡張性のある音源エンジンおよびドライバを作りたいと思います。プロジェクトとしては時間がかかるとは思いますが、新規音源ドライバで「新しい音」を作れればこれ以上ない幸せです。
2002.08.11 : 音源ドライバのコンセプト
・ 単純なモジュール(プラグインで拡張可能)を組み合わせ、音源そのもののアルゴリズムを作ることが可能
音源そのものの構造を、正弦波モジュール、矩形波モジュール等のPCM発生源やエンベロープジェネレーターモジュール、FM合成モジュール、エフェクタモジュール等を組み合わせて合成することが可能です。またそれぞれのユニットはプラグイン形式で拡張可能とします。
・ 仕様上の制約なし(すべての要素は可変長)
曲のパート数や音源のユニット数は可変長とし、原則として制限はCPU速度とメモリ以外には存在しません。
・仕様変更を恐れない
安定するまでは頻繁に仕様が変更される可能性があります。過去にとらわれて煩雑なものになってしまうより、すっきりして見通しの良いドライバとしたいと思います。
また、仕様変更が出来ないとその分設計をじっくり煮詰める必要があり、いつまでもモノが出てこない可能性があるので、それより設計→実装→検証のサイクルを早く回して不具合を洗い出したほうがいいものが出来るのではないかと思いますし、作っているほうも気が楽です。
2002.08.11 : ソフト構成
- シンセサイザ
シーケンサや音色エディタからの命令を解釈しPCM を生成します。モジュールのプラグインDLLも含まれます。
- シーケンサ
曲データを解釈し、シンセサイザに命令を発行し、PCMを生成します。
- MMLコンパイラ(未定)
MML(ファイル or メモリ or ストリーム)を受け取りバイナリデータを生成します。
ファイルを生成せずにメモリで受け渡しすれば擬似インタプリタも可能。
- フロントエンド
(1)〜(3)を制御するプレイヤ、WinAMPやkbMedia Playerのプラグイン、作曲ツール、音色エディタ等が考えられます。
(1)〜(3) は DLL として作成する予定です。
例1:プレイヤ
![]()
例2:作曲環境
2002.08.11 : シンセサイザの概念図
シンセサイザができないと音が出ないので、まずはシンセサイザを設計、実装することにします。
シンセサイザの概念図として、2opFM音源の例を図示します。
2002.08.11 : シンセサイザの仕様(概要)
オブジェクト指向の教科書にのっとって仕様を日本語で箇条書きにしてみます。
この段階の仕様書としては細かすぎるかもしれませんが、作りたいものがある程度決まっているので気にしないことにします。
- シンセサイザは DLL として提供され、ホストプログラムからの命令を解釈して PCM を生成する。
- シンセサイザは1曲演奏時に内部で Music オブジェクトを生成し、演奏終了時に破棄される。同時に2曲以上を演奏(レンダリング)することも想定し、Music オブジェクトを複数生成することもできる。
- メインパート、ベースパート、等、1パートごとに Part オブジェクトを生成する。1パートでは1音のみを演奏できる。そのパートがなくなれば Part オブジェクトは破棄される。なお、Part オブジェクトは曲の演奏途中でも生成/破棄することができる。
- Part オブジェクトは1つ以上の Module オブジェクトからなる(モジュールオブジェクトはプラグインDLLとして実装)。Module オブジェクトの例として、Sin 波生成オブジェクト、エンベロープオブジェクト、FM 変調オブジェクト等があげられる。Module オブジェクトは0個以上の他のModule オブジェクトと接続し、他の Module オブジェクトのPCM 出力から自分自身のPCM 出力を計算し、出力する。なお、Module の接続の組み換えは曲の演奏中でも可能とするが、Part / Music オブジェクトをまたがってはできないものとする。
2002.08.11 : クラス図1
手始めにクラス図を描いてみます。こんな感じでしょうか?
2002.08.18 : Module クラスについて
Module クラスの動作について箇条書きで記してみます。
- Part クラスから使用されるときに生成される。種別を識別するためにモジュール名(Sin, Envelope, FM 等)を使用する。→モジュール名から生成オブジェクトを割り出すのは別のクラスの役割?
- その際に初期値を設定されることがある(例えばサンプリング音を演奏するために「wave演奏クラス」を導入した場合、「waveファイル名」を指定する必要がある)。
- 演奏前に他の Module クラスのオブジェクトあるいは Part モジュールのパラメーター(Frequency, Keyon/Keyoff, Volume 等)と接続する。Sin オブジェクトなら「駆動周波数(Frequency)」の1つですむが、FM オブジェクトの場合「変調される波形」と「変調する波形」の2つ必要。
- PCM 取得の指示を受けたら接続先のパラメーターを元に PCM を生成し、出力する。
- 使われなくなったら破棄される。
クラスの初期値の代入に InitValue() メンバ関数を設けることとします(文字列、整数オーバーロード)。その際、クラスの入力としてどのようなパラメーターを何個取るかを GetFormat() の戻り値で指定します。他のオブジェクトとの接続は Connect()、PCM の計算に Calc() を用い(接続先の呼び出しを Calc()で行い、自分の計算は DoCalc() で行う)、計算結果を GetValue() で取得することとします 。また、また、モジュールのバージョンを GetVer() で取得できるようにします。
GetFormat() はモジュールがどのような引数をどれだけ取るかを文字列で返します。C 言語の printf() 等で使用される書式制御文字列類似としますが、下記の形式のみ使用可能です。
- %d : 整数
- %s : 文字列
- %m : 他のモジュール(接続用)
- %f : 他のモジュール(即値) //2002.09.16 仕様拡張
ex)"%s%d%d%m%m" : 文字列を1つ、整数を2つ、他のモジュールの出力を2つ取ります。
実際のモジュールの初期値の設定は InitValue() を用い、下記のように記します。
- InitValue(0, "test.wav"); // 文字列の初期値(0番目)を「test.wav」に設定します。
- InitValue(1, 12345678 ); // 整 数の初期値(1番目)を「12345678」に設定します。
1つ目の引数は GetFormat() の何個目のパラメーターに対応しているかを示します。整数、文字列で別々に管理され、最初のパラメーターを「0」とします。GetFormat() で指定されたパラメーター数を超えた値を設定した場合、あるいは初期値が不正の場合はエラーが返ります。 InitValue() で値を設定した後、実際の初期化作業は Init() を用います。Module オブジェクトはメモリの確保やテーブルの作成等、必要な作業を行います。
Module と Part モジュールのパラメーターを同等に扱うために、計算結果を保持する CalcBase クラスをベースクラスとして、そこから初期値の定義/設定、接続の機能を実装した ConnectBase クラス、さらにバージョン情報を実装した Module クラスを派生します。また、パラメーター用に CalcBase クラスから PartParam クラスを派生させ、Part クラスはConnectBase クラスから派生させます。
モジュール同士の接続には Connect() を用います。Module1.Connect(0, Module2) で、Module2 の結果を Module1 の0番目のパラメーターとして用いるようにします。その後、Calc() で計算を行い、GetValue() を用いて実際の値を取得します。
なお、GetFormat(), GetVer(), Init(), DoCalc() メンバ関数は純粋仮想関数とし、派生先で実装します。
2002.08.18 : クラス図2
早くも複雑になってきました。継承使いすぎかも・・・
2002.08.18 : ソース Ver0.01
DownLoad : newmusicdriver001.lzh (19,760bytes)
VC++ 6.0 用。ソースのみです(正弦波のベタファイルを吐き出すだけなので)
試しに 100モジュール、10秒分の計算を行ってみたところ Pen4、1.8G で12秒かかってしまいました。今後、多少は軽量化できるかな?
今後の課題:
- Calc / GetValue の整理
- モジュールの DLL 化。モジュール名からのモジュール生成機構、プラグイン管理法の決定
- フィードバック実現時の無限ループ対策
- Calc 実現時の if 多用によるパフォーマンス低下対策
- Module を使用していない時のパフォーマンス低下対策
- InitValue() / Connect() を番号ではなくて文字列で指定できるようにする?
- エラー対策(初期値が設定されていない、Module が接続されていない、etc.)
2002.08.25 : モジュールクラスの修正&速度分析
前回のクラス図だとインターフェイスクラスを導入すると多重継承が必要となり、COM 風インターフェイスを使用できずモジュールの DLL 化が不可能なことに気づいたので、クラス図を単純化して DLL 化できるように変更した。
また前回の速度の計測は腕時計で計っただけの手抜きだったので、テストコードを書いてみてまじめに計測した。条件は前回とほぼ同様(前回は1つのモジュールを使いまわしたけど今回はまじめに100個作ってみた。メモリスワップの影響があるかもしれないので)。
モジュールに手を加えない場合(Ver0.01のソースそのもの)
12.032sec
Sinモジュールの Sin 演算をカットし、常に 1.0 を返すようにした場合
6.641sec
さらに位相の計算もカットした場合
5.531sec
さらに結合されているかどうかのチェックもカットした場合
5.359sec
やはり Sin 演算のコストが最も大きく他はそれほどでもないようだ。ただ現行の Calc() 実行毎に結合チェックを実行する現行の方法だと多少なりとも時間をとられるので、モジュールの生成、結合、初期化等の操作はすべて Part クラスのメソッドを使用して行うようにし、Part クラスでモジュールの生成、結合が行われたかどうかをチェックして前回と変わらなければチェックを省略するようにしようと考え中。どこまで公開してどこを隠すか、実行速度とソースの綺麗さのバランスをどう取るか悩みどころ・・・
2002.08.31 : モジュール読み込み
モジュール読み込み部分の設計開始。ModuleManager クラスを設けてモジュールの読み込み、一括管理するようにする。COM 風インターフェイスを介してモジュールを生成するのもこのクラスの役割と。
外部ソフトからのモジュールの識別なんだけど、さすがに MML に GUID を埋め込むのは嫌なので(苦笑)、やはり文字列で識別したほうがいいのかな?
2002.09.02 : モジュール読み込みその2
モジュールの COM 風インターフェイス化はほぼ終了(PMDWin のソースを引っ張り出してきて書き換えるだけなので)。ModuleManager で例外を使おうとして調べていたら夜遅くなったので中断。今まで C++ では例外を使ったことなかったからなぁ・・・
2002.09.09 : モジュール読み込みその3
例外処理については Web やら STL のソースやらを探して何とかコンパイルできるようになった。
STL について基礎から理解したいと思ったので本を買ってきた。STL は Vector や List 単体を覚えるだけでもかなり使えるが、アルゴリズム等はいろいろな組み合わせがあるので慣れが必要そうだ。
オブジェクト指向、UML、C++らしいコーディング、STL など、自分にとっては新しくてマスターしたいことをすべてつぎ込んでいるのでなかなか進まない・・・
2002.09.17 : クラス図3
インターフェイスクラスを導入し、Module のプラグインを実装しました。また実装クラスのほうは若干階層を減らしました。COM風インターフェイスを導入すると多重継承が出来ないので一部苦しいところがあるけどこんなものかな?
シンセサイザ側からのモジュールの生成/操作は Part クラスのメソッドでモジュール名を指定して行い、IModule は使えないようにしました(IModule が使えると内部の動作をいじれるので危なすぎる)。IModule は主にモジュールを作るときに必要になるものです。
(画像をクリックすると拡大します。とうとう実寸だと入りきらなくなってしまった)
せっかくプラグイン機構が実現できたので正弦波、矩形波、ノコギリ波(右上がり/右下がり)、足し算、掛け算、即値のモジュールも作成しました。原理的には単純な音は作れると思います(エンベロープがないので辛いけど・・・)
ただし、シンセサイザ自身の DLL 化がまだなので現時点では C++ のコードを書く必要があります。
2002.09.17 : ソース Ver0.02
DownLoad : newmusicdriver002.lzh (313,417bytes)
VC++ 6.0 用。ソース+テスト用サンプルプログラム(正弦波のベタファイルを吐き出すだけ。振幅×0.5)
2002.09.20 : ちょっと見直し
今のモジュールの仕様だと正弦波ユニットを使って FM 変調ができないことに気づきました。あぅ・・・勘違い(というか思い込み)でした。
あと、ひとつの DLL に複数のモジュールを登録できないとライブラリの重複のムダが多すぎるので、ちょっと手直しして複数登録できるようにしようと思っています。
2002.09.29 : FM変調
ライブラリの仕様を一部見直し、ひとつの DLL に複数モジュールを入れられるようにした。また、モジュールも見直して位相出力モジュール(Phase)を導入し、正弦波ユニット、矩形波ユニット等は位相データから演算するのみとした。
早速 FM変調を作ってみたところ変調がかかった音が鳴ってきたので多分うまくいっているのだろう。
2op、フィードバック付きのFM音源の配置図(ハッチングがかかっているモジュールでパラメーターを設定しています)
2002.10.14 : Music オブジェクト
外部のプログラムから操作できるようにするために、さっさと Music オブジェクトを作ることにする。Musicオブジェクトそのものはたいした機能はないんだけど、Part を管理し、生成された音データの音量を調整して pan を振る機能と、エラーオブジェクト(実体はただの文字列だけど)との関連を張る機能が主なものかな。
さらにシンセサイザモジュール全体を DLL 化して他のソフトから操作できるようにした(はず・・・だけど試していないので不明)。
今のところ、正月の冬休み明けにテキストレベルの音色エディタを作るのを目標に作っていこうと思っています。
2002.10.28 : 外部アプリケーションからの制御
Delphi で作ったテストプログラムからシンセサイザの制御を試みるが謎のアクセス違反が出て落ちてしまう。いろいろ試してみたが DLL 側の問題かテストプログラムの問題か判別が付かなかったので、C++でもテストプログラムを書いてみたところこちらは問題なし。散々悩んだ結果 Calc メソッドでバッファへのポインタを引数にとらないといけないのに配列型(Array of 〜)を使っていたためと判明。その他細かい不具合を修正してやっと音が出るようになった(正弦波しか出していないけど・・・)
2002.12.23 : 最近の状況
2ヶ月ほったらかしにしてしまいました・・・
久しぶりに再開。Delphi で作ったテストプログラムで wave を吐けるようにしたのと、シンセサイザ本体のエラー処理の実装を行った。エラー処理をまじめにしないとアクセス違反や浮動小数点エラーで落ちかねないので重要である。
エラー処理は Music オブジェクトで生成した ErrMsg / ErrPart / ErrModule オブジェクト(実体はすべて char の配列)にエラーメッセージ、エラーを起こした Part 名、エラーを起こした Module 名を代入して、return でエラーに対応する値を返すだけ・・・。例外を throw するのが C++ 風なんだろうけど、COM インターフェイスを通して例外を投げることができるかどうか不明だったので無難な方法で。また ErrMsg 等のオブジェクトを真面目にクラスにした方がアクセス違反をしなくて安全なんだけど、エラーメッセージ格納のためだけにインターフェイスを作るのも面倒なのでパス。
2002.12.30 : 最近の状況2
冬休みになってやっとまともにプログラミングできるようになった。先週エラー文字列を char の配列で実装したが、長さに制限が出来るのとアクセス違反の危険性があるのが気に入らずクラスで作り直し。これだけで3時間かかってしまった・・・
こんなことしているからいつまでたっても完成しないのかも(^^;
2002.12.31 : エラーメッセージの代入
昨日使ったエラー文字列用クラスにエラーメッセージを代入するところの実装を考え中。
後々のことも考えて少しでも汎用的に作りたいところ。数字や文字列を出力する場合でもエラーメッセージを1つの文字列で定義したいので、strstream 系ではなく sprintf 系がいいのだけど、sprintf では出力バッファのサイズを事前に決めないといけないので使いづらい。sprintf の C++ 版(戻り値が char* でなくて string)があれば一番いいのだがインターネットに接続できないので探せない(;_;)。自分で作るかなぁ。
2003.01.01 : エラーメッセージの代入その2
string 版 sprintf についてgoogle で検索したところ、C++ ライブラリの Boost にそれっぽい機能がありそうだが実家の電話線環境ではダウンロードもままならず、結局関数オーバーロードと引数付きマクロで実装した。
やっと文字列が出せるようになったのでエラーメッセージの定義をしてテストをすることにする。
2003.01.05 : クラス図4
(画像をクリックすると拡大します)
ラッピング用に Synthesizer クラスをつくり、ErrStr オブジェクトも Synthesizer クラスで管理するようにした。また、エラーメッセージも主なものは定義、テストを完了した。シンセサイザの細かい不具合は何点かあるが、手直しは後回しにしてテキストファイルで音色を定義して鳴らせるようにすることにする。
2003.01.05 : ソース Ver0.03
DownLoad : newmusicdriver003.lzh (84,272bytes)
VC++ 6.0 用(シンセサイザのソース)/Delphi 4.0 以降用(サンプルプログラムのソース)
2003.01.05 : サンプルプログラムの実行ファイル Ver0.03
DownLoad : newmusicdrivertest003.lzh (285,818bytes)
相変わらず正弦波だけだけど、音量、音程、パンが変えられるようになりました。
2003.01.07 : 音色定義の仕様
テキストファイルで音色を定義するために仮のフォーマットを決定した。.
1.注釈
// ・・・ (一行注釈)
/* ・・・ */ (範囲注釈、複数行も可能、ネストは不可能)
2.文字列
" ・・・ "
複数行は不可。文字列には特殊文字(改行、ダブルクオーテーション等)を含むことはできない。
3.式
演算子(+, -, *)、数字(モジュール型)、括弧を使用できる。複数行にまたがる記述も可能。
4.音色定義(案)
4−1.単純な正弦波
neiro neiro1{
// モジュール生成
sin sin1;
phase phase1;
// モジュール接続+ベースモジュール設定
out(sin1(phase1(key, freq)));
}
4−2.2op FM
neiro neiro2{
// モジュール生成
immediate op1_ML, op1_TL, op2_ML, op2_TL, FB;
sin op1_sin, op2_sin;
phase phase1;
// 初期値設定
op1_ML.module( 2.0);
op1_TL.module( 0.0);
op2_ML.module( 1.0);
op2_TL.module(10.0);
FB.module(1.0);
// モジュール接続+ベースモジュール設定
Phase1(key, freq);
op1_sin(FB * op1_sin + Op1_ML * Phase1)
op2_sin(op1_TL * op1_sin + op2_ML * Phase1)
out(op2_TL * op2_sin)
}
まんま C++ / JAVA 系のクラス定義の真似です(^^;;;
Cマガジン 2003/1月号の特集(コンパイラの作成)を参考にして音色定義ルーチンを作成することにする。
手始めに注釈、数字、演算子、括弧以外のモジュール定義、初期値設定、接続、ベースモジュール設定の基本的な部分のみ実装することにする。
2003.01.12 : 音色定義用 DLL の仕様(概要)
例よって仕様を日本語で箇条書きにしてみます。
- この DLL は、引数として音色のテキストデータと IPart を受け取り、IPart に音色を設定するものとする。 名称は SetNeiro.dll とする(安直やなぁ)
- DLL では、まずテキストデータの字句解析を行い、テキストデータをトークンに分割する。次に構文解析を行いトークン列より構文木を作成する。その後に構文木の妥当性を検討し、最後に構文に従って音色を設定する。
- 音色の構文は上記の仕様(2003/01/07 の日記に記載)とする。
とりあえずクラス図を描いてみるとこんな感じ。
2003.01.27 : 音色定義テキストの構文解析の進捗状況
とりあえず字句解析部は作りました。
構文解析部の設計に入ったところだが、初めて作るのでなかなかうまくできないです。
将来的には MML コンパイラの音色解析部分に使いたいため、拡張性、汎用性のある作りにしようとしているので余計にハマているっぽいです(苦笑)
2003.02.03 : 構文解析部の設計
Cマガジンの記事を参考にしながら構文解析部を実装中。
構文解析部の1/3くらいできたかな・・・
現在のクラス図は下記の通り(以前と全然変わってしまいました)
2003.02.09 : 構文解析部の設計その2
基本的な構文解析はできるようになりました。四則演算等はまだ組み込んでいませんが。
やっと音色定義の実装に入れます。
クラス図はまた微妙に変わってしまったんだけど次の機会に・・・
2003.02.17 : 構文解析部の設計その3
音色定義その他を組み込んで、やっと設定文字列に従って音が鳴るようになりました。
いろいろ試していると今まで手を抜いていたところでエラーが出るようになったので、
メモリ開放やエラーチェックをちゃんと実装して公開したいと思います。
2003.03.02 : 構文解析部の設計その4
エラーチェックや細かいところの修正が済んだので公開します。
クラス図は結局下記のようになりました(クリックすると拡大します)
2003.03.02 : ソース Ver0.04
DownLoad : newmusicdriver004.lzh (108,555bytes)
VC++ 6.0 用(シンセサイザ/基本モジュール/音色定義用 DLL のソース)/Delphi 4.0 以降用(音色定義プログラムのソース)
2003.03.02 : サンプルプログラムの実行ファイル Ver0.04
DownLoad : newmusicdrivertest004.lzh (354,934bytes)
やっとテキストで音色定義ができるようになりました。
2003.03.09 : 構文解析部の設計その5
ExpressionNode を拡張して四則演算の実装を行うことにしました(さすがに足し算をするのに「add(a, b);」だとアセンブラ並に記述性が悪いです)。
例によってCマガジンの記事を参考にして演算子順位構文解析法で実装しました。エラー処理を組み込むのに苦労しましたが、構文解析部はほぼ終わりました。
後は演算子に名前をつけて音色定義部を実装すれば動きそうです。
2003.03.22 : 構文解析部の設計その6
構文解析や演算子や即値の(内部的な)命名、音色定義のために3つクラスが増えました。
アルゴリズムが複雑になって思いの他難儀したが、やっと動くようになりました。
段々ソースが汚くなってます(;_;)
2003.03.22 : ソース Ver0.05
DownLoad : newmusicdriver005.lzh (69,893bytes)
VC++ 6.0 用(基本モジュール(Sub, Div モジュールの追加)/音色定義用 DLL のソース)
2003.03.22 : サンプルプログラムの実行ファイル Ver0.05
DownLoad : newmusicdrivertest005.lzh (98,956bytes)
基本モジュール/音色定義用 DLL のみです。Ver0.04 に上書きしてください。
2003.03.24 : 構文解析部の設計その7
Ver0.05 で phase(1, 10) のように関数内に即値あるいは演算子を2つ以上書くと内部名が重複してエラーが起きてしまうというしょ〜もない設計ミスを修正したので、急遽 Ver0.06 として公開します。
2003.03.24 : ソース Ver0.06
DownLoad : newmusicdriver006.lzh (26,038bytes)
VC++ 6.0 用(音色定義用 DLL のソース)/Ver0.05 に上書きしてください。
2003.03.24 : サンプルプログラムの実行ファイル Ver0.06
DownLoad : newmusicdrivertest006.lzh (74,811bytes)
基本モジュール/音色定義用 DLL のみです。Ver0.05 に上書きしてください。
2003.04.13 : SMF テスト演奏プログラムの設計その1
やはり「音楽」が鳴らないと寂しいので SMF を鳴らすテストプログラムを作成することにした。
あくまでテストプログラムなので音色は1つのみ。
まずは SMF を保持するクラスと SMF をトラックに分割して保持するクラスのコーディングを開始した。
2003.04.16 : エラーメッセージオブジェクト格納場所の手直し
SMF テスト演奏プログラムの設計を行う中でエラーオブジェクトの不具合に気づいた。
プレイヤからテストプログラム(シーケンサー)の DLL を読み込み、テストプログラムからシンセサイザの DLL を読み込む場合、従来の設計ではシンセサイザがエラーオブジェクトを保持しているためシンセサイザからシーケンサーのエラーオブジェクトに書き込みを行うことができず、その結果シーケンサーでも別にエラーオブジェクトを保持する必要があり、プレイヤ側から参照するのが面倒であった。今回シーケンサー、シンセサイザの外部にエラーオブジェクトを保持するように修正した。
2003.04.20 : SMF テスト演奏プログラムの設計その2
クラスを一通り作り(中身は入っていないけど)、コンパイルだけは通るようにした。
これでやっと SMF 解析部の動作テストができます。
2003.04.29 : SMF テスト演奏プログラムの設計その3
SMF のイベントのうち、演奏に必須なもののデコードルーチンの作成を終了した。
次いでシーケンサ部分のプログラムに取り掛かった。
2003.05.05 : SMF テスト演奏プログラムの設計その4
シーケンサ部分の設計を行っているところだがどうもしっくりこない。
SMFファイルのヘッダ情報を保持する SMF クラスとトラック情報を保持する Track クラスは、もともと SMF クラスから Track クラスへの単方向の関連にしていたんだけど、Track クラスでテンポを変えたときに全体のテンポを変えないといけないのでテンポの情報を SMF クラスに持たす必要があるため双方向の関連にしないとダメっぽい。
(Track クラスのクラス変数にする方法もないわけではないけど、同時に複数の SMF ファイルをデコードすると破綻するのでクラス変数は使わないことにしている)
他にうまい方法が思いつかないので仕方なく双方向にした。
シーケンサ側は最低限の機能は実装したのでプレイヤ側を実装してテストしてみることにする。
2003.06.29 : SMF テスト演奏プログラム設計その5
いろいろ手直ししてとりあえず演奏が出来るようになった。
演奏の精度は全然気にしていないのでボロボロだけど(苦笑)
メモリのハンドリングやエラー周り、プレイヤの UI を手直しして公開する予定。
#その前に WinFMP / PMDWin を直さないと(^^;
2003.08.13 : SMF テスト演奏プログラム設計その6
一通りバグフィックスが終わったので公開します。
UMLは以下のようになりました。
2003.08.13 : ソース Ver0.07
DownLoad : newmusicdriver007.lzh (39,581bytes)
SMFTest とテストプログラムのソースです。
2003.08.13 : サンプルプログラムの実行ファイル Ver0.07
DownLoad : newmusicdrivertest007.lzh (240,654bytes)
バージョンがごちゃごちゃしてきたので一通り入れています。
非常に重いので Pen4 クラスの CPU を推奨します。
2003.08.17 : 夏休みの成果
NewMusicDriver のバージョンアップ。SMFTest が一応動くようになった。
OPN 相当の機能を取り込みために FM 合成のパラメーター取得の準備。fmgen のソースはビットシフトが多くて読みづらいので MAME のソースでテストプログラムを作成。正弦波が出力されるところまでは確認した。
DLS モジュールを作成するための英文ドキュメントの読解開始。
PCM 関係のモジュールの作成開始。ここから派生させて WAVE や DLS、SCC のモジュールを作成する予定。
VC++ のプロファイラによる実行速度計測にトライ。Synthesizer / SMFTest 等の関数単位でのプロファイルはできるようになったが、なぜか BasicModule だけできない・・・仕方がないので後回し。
WinFMP / PMDWin のバージョンアップ。
小物プログラム(謎)の作成。
2003.08.31 : WAVE 関係のモジュールについて
モジュールクラスとして PCM クラスを作成し、派生させて WAVE クラス、WaveMemory クラス(波形メモリクラス)を作成した。
とりあえず動くようになったが全体の設計にかかわる問題が2つ明らかになったので今後全体の見直しも含めて再検討を行う予定。
2004.01.04 : 冬休みの成果
モジュールの追加、エラー処理の改善、若干の高速化、その他いろいろ。多すぎて覚えていない・・・
2004.01.04 : ソース Ver0.08
DownLoad : newmusicdriver008.lzh (158,348bytes)
一式入っています。
2004.01.04 : サンプルプログラムの実行ファイル Ver0.08
DownLoad : newmusicdrivertest008.lzh (408,247bytes)
こちらも一式入っています。
Ver007 の Delphi のテストプログラムが VCL とリンクせずにコンパイルしていたことが判明(^^;
こちらはスタティックリンクなので単体で起動できるはずです。
2004.01.17 : ちょっと手直し
Ver0.08 で Synthesizer の不具合が表面化した(Part::Enabled が false の時も演奏してしまう)のを修正した。
一部の MIDI メッセージを素通しするようにした。
SMFTest の内部構造の見直し。
NewMusicDriverTest をちょっと強化(演奏スレッドの優先順位を設定できるようにし、ウィンドウのサイズも記憶するようにした)
2004.01.17 : ソース Ver0.09
DownLoad : newmusicdriver009.lzh (94,828bytes)
Ver0.08 に上書きしてください。
2004.01.17 : サンプルプログラムの実行ファイル Ver0.09
DownLoad : newmusicdrivertest009.lzh (305,059bytes)
こちらも Ver0.08 に上書きしてください。
2004.05.05 : GWの成果
以前から手がけていた設計の見直しとして、モジュール、パート等から共用して使用できるユーティリティーの「サービス」を導入した。
今回はエンベロープモジュールのデジベル→リニアテーブルの共用だけだが、将来的にはファイルアクセス等もサービスを利用して行う予定。ホストプログラム(プレイヤー等)からファイルアクセスサービスを実装・登録することによって、単純なファイルだけでなく圧縮ファイルや ftp 等によるデータの取得も可能。
サービスの実装に手間取ったのとバグが取れなかったので伸び伸びになってしまったが、やっと動くようになったので公開。あちこち手を入れたので、だいぶんまともに動くようになって来たかな。
次は本格的に OPN アルゴリズムを組み上げるか、それとも MML 作成に入ろうかな?
2005.05.05 : ソース Ver0.10
DownLoad : newmusicdriver010.lzh (166,642bytes)
一式入っています。
2004.05.05 : サンプルプログラムの実行ファイル Ver0.10
DownLoad : newmusicdrivertest010.lzh (459,649bytes)
一式入っています。これだけで動くはずです。
2005.05.09 : バグ取り
SMFTest で曲によってアクセス違反が発生するバグと無限ループになるバグを FIX しました。
2005.05.09 : SMFTest のソース
DownLoad : newmusicdriver011.lzh (28,255bytes)
Ver0.10 に上書きして下さい。
2004.05.09 : SMFTest.dll
DownLoad : newmusicdrivertest011.lzh (58,575bytes)
こちらも Ver0.10 に上書きして下さい。
2004.08.15 : 夏休みの成果
あまり進まなかったんだけど、OPN(相当)のアルゴリズムの組み上げと SMFTest の改良(曲長計算(暫定)、再生位置取得/設定)、NewMusidDriverTest の改良(自動調整の改良、再生位置の表示、「Save」時に音を出さないようにした、など)を行いました。
OPN アルゴリズムは重すぎる・・・リアルタイムだと 22kHz 合成でも3音鳴らせるかどうかです。
指数関数を5個、対数関数を1個使っているのが問題だよなぁ。
2005.08.15 : ソース Ver0.12
DownLoad : newmusicdriver012.lzh (130,107bytes)
BasicModule, SMFTest, NewMusicDriverTest が入っています。Ver0.10に上書きしてください。
2004.08.15 : サンプルプログラムの実行ファイル Ver0.12
DownLoad : newmusicdrivertest012.lzh (421,715bytes)
一式入っています。これだけで動くはずです。
2005.09.04 : 久々に再開
1年以上放置していたが、遅ればせながら MML での演奏に対応することにした。まずはソースを眺めてリハビリに努める。その後、今後に備えてソースの手直し。かなり書き直したかな・・・表向きの動作はまったくと言っていいほど変わっていないのですが。
テストプログラムもちょっと見直してテキストを外部のエディタでも編集できるようにしてみた。かなり便利かも。
2005.09.24 : MML 部実装中
遅ればせながら MML の実装を開始。まずは MML の字句解析を実装。MML 以外の部分と字句の区切りが全く異なるので MML 内部かどうか判別して処理を分割した。ドライバの仕様上、MML 内部にも実数を書く必要があるんだけどシャープ、フラットや音長の付点(「a-8.」とか)との判別が難しい。仕方がないので実数は符号ありだけど整数は符号なししか書けない仕様に。後で仕様変更が必要になるかも。
次いで構文解析の実装開始。MML の解析はコンパイラとして実装するつもりだったが時間節約のためインタプリタで実装予定。現在のところ、音符、休符、テンポ、オクターブ設定の構文解析部の実装を終了。
UML モデリングは今まで Rational Rose のデモ版を使っていたんだが、クラス数の上限に到達してしまったので別のツールを探索し、1st Modeller に乗り換えた。モデルの書き直しで少し時間がかかってしまった。
2005.10.02 : インタプリタ/シーケンサの設計
MML による音楽演奏時の制御(音程や音長の確定、シンセサイザの制御等)をインタプリタ内の音符オブジェクトや休符オブジェクト等で行うか、シーケンサで行うかで悩む。オブジェクト指向的には音符オブジェクトや休符オブジェクトで行うほうがいいのは間違いないんだが、そうするとインタプリタとシーケンサの分割が不可能になって見通しが著しく悪くなってしまう。一方シーケンサ内で制御を行うと折角インタプリタで構文解析したのにシーケンサ内でもオブジェクトの判別処理を行わないといけないので無駄が生じてしまうばかりでなく、処理が2箇所に分かれてしまう。
2日ほど考えた結果、ソースの見通しや実装容易性を考慮し、シーケンサ内で行うことにした。
2005.10.30 : インタプリタ/シーケンサの設計その2
MML 構文解析部のソース手直しやエラーチェックを実装。解析された MML オブジェクトをシークするのをどうするか考え中。構文解析部でそのままシークすることはできないことはないのだがループ等を考えると非常に大変そう。今のところポインタ配列に MML オブジェクトのポインタを演奏順に格納しておきこれでシークしようと思っているがうまくいくかどうか・・・
2006.01.15 : インタプリタ/シーケンサの設計その3
結局、インタプリタ部分とシーケンサ部分の連結は上記の通りに実装。その他色々実装して、やっと MML から音が鳴らせるようになった。今のところ対応しているコマンドは cdefgab,r,t,v,@,o,<,>,q,l,&,p,(,)。あとループとベンドに対応したら公開しようかなぁ。
2006.04.23 : MMLバージョンの公開
ループに対応して細かいバグをつぶしたので公開します。結局ベンドは未実装。
2006.04.23 : ソース Ver0.13
DownLoad : newmusicdriver013.lzh (170,516bytes)
Synthesizer, BasicModule, MMLInterpreter, NewMusicDriverTest が入っています。これだけでコンパイルできます。
2006.04.23 : サンプルプログラムの実行ファイル Ver0.13
DownLoad : newmusicdrivertest013.lzh (373,085bytes)
一式入っています。これだけで動くはずです。サンプルがしょぼくて全然能力を出せていませんが・・・
2006.07.09 : ベンドの実装
遅くなりましたがベンドを実装。Envユニットを修正して LFO 関係を使いやすくしたら公開予定。
2006.08.20 : Envユニット修正
Envユニットのスケールとして、db 単位と Linear 単位を選択できるように修正。またマニュアル(簡易的なものだが)を作成した。そろそろ DownLoad ページに移してもいいかなぁ?
2006.08.20 : ソース Ver0.14
DownLoad : newmusicdriver014.lzh (167,794bytes)
一式(更新していないものも)入っています。
2006.08.20 : サンプルプログラムの実行ファイル Ver0.14
DownLoad : newmusicdrivertest014.lzh (395,684bytes)
一式(実行ファイル+MMLマニュアル(NewMusicDriver.txt))入っています。
2008.06.08 : ソース Ver0.15
DownLoad : newmusicdriver015.lzh (268,663bytes)
大幅な見直しの前の安定Ver?。一式入っています。
2008.06.08 : サンプルプログラムの実行ファイル Ver0.15
DownLoad : newmusicdrivertest015.lzh (682,444bytes)
一式(実行ファイル(SMFTestPlayer, NewMusicDriverTest)+MMLマニュアル(NewMusicDriver.txt))入っています。