● 実験テーマ113

「大昔自作した、音楽シュミレータ・ソフトを、KM-BASICへ移植する実験」 
(1985年頃、PC-8801mkUmr+N88-BASICにて自作したソフトを、KM-BASICへ移植する実験です)

※ 190328:
   2回目の更新です。
   以下を、追加しました。
   @ 第7弾:MUS_SUM3(音出し追加)
   A 第8弾:MUS_SUM4(SDへのSAVE追加)
   B 第9弾:MUS_SUM5(音符データ呼出し追加)

※ 2019年3月7日からの記事を参照してください。


※ 190219:
   第6弾:「簡易版の、音符入力処理・描画」の、追試を行いました。
   未だ音は鳴りませんが、5線譜上に、音符入力・描画が、出来るようになりました。
   但し、入力できる音符種等、限定した簡易版です。

  ※ 2019年2月6日からの記事を参照してください。


■ 2018.12.30
 
 ・大昔自作した、音楽シュミレータ・ソフトを、KM-BASICへ移植してみようと思い立ちました。
   大昔の物なので、当時設計に残した資料は、手書きの各種設計書と、両側に、フィード用の孔の空いた
   プリンタ用紙に印刷された、プログラム・リストのみでした。
   約34年前の物なので、資料の紙も、かなり黄色ばんで、傷んでいました。

   残された、プログラム・リストも、何種類かあり、日付が明記されてないので、どれが最新版であるか
   判らない状態でした。
   大きく分けると、音楽データを保存する媒体が、カセット・テープのと、5インチFDDが、ありました。
   なので、5インチFDD版が、最新と判断し、このリストから紐解いて、作業を進めることにしました。

  ・ここで、当時考えた、当ハード・ソフトの概要を、思いつくまま、説明したいと思います。
   <
音楽シュミレータ:ハード・ソフトの概要>
    (1) ハード構成
      @ 
PC
         PC-8801mkUmr

      A 音源ボード(背面スロットに増設)
         GSX8800(General Sound eXpanber):HAL研究所社製
         → サウンドPSG・IC:AY-3-8910:GI社製 2個搭載

    (2) 音楽シュミレータ・ソフト概要
      ・当時、未だ、SC-88Pro等の音源を使った、音楽制作はしていませんでしたが、パルス・ソースを基にした
       PSGを使っての、音符入力による、譜面作成ソフトには、大変興味がありました。
       PCの、ディスプレイに、楽譜を表示してみたいというのが、最初のきっかけでした。

      <自作ソフトの、仕様(というか、動作仕様)概要>
       @ メインメニューは、こんな感じです。(手書き設計書からの抜粋を以下に示しました。)
          以下は、カセット・テープに、データ保存する版の、ものです。

       A 音符入力画面は、こんな感じです。 (手書き設計書からの抜粋を以下に示しました。)

       B 音符の各種パラメータ(長さ・音程・音域・休符か通常の音符の区別等)入力から
          音符描画位置を判断し、指定位置に、臨時記号があればそれを含めた音符を描画する。
          以下に、手書きで汚いですが、そのルーチンのフローを示しました。

          また、以下に、音符配置の計画図例を示しました。

       C 以下に実際入力が完了した楽譜の画面のハードコピーを、プリントアウトしたものをアップしました。
          これが参考になると思います。


       D 音符を、5線上に置くと、その音を再生します。
          入力途中までの、曲を再生することもできます。
          また、フロッピーへのセーブも可能です。
          音出しの、ソフトの基は、サウンド・カードに付属の、ソフトを使っています。
          PLAYコマンドが、それです。
          PLAYコマンドは、GSX-8800で、6重音までの音楽を演奏させるものです。
          入力された音符パラメータ( 長さ・音程・音域・休符か通常の音符の区別等)を、記号化した
          文字(Music Macro Languege:MML)を、PLAYコマンド内に組込むことにより音楽を演奏させます。

          書式(1声譜の場合):PLAY "MML"
          MMLの要素例を、以下に示しました。   

   


■ 2019.1.13
 
 ・プライベートで、色々とバタバタした新年となった為、新年に入ってから暫くは作業できませんでした。
   少し落ち着いて来たので、移植作業を再開しようと思います。
   いきなり、同じ機能を盛り込むのは、結構量があり、大変なので、小さな機能に小分けして進めようと
   思います。

  ・まずは、第1弾として、「五線に、ト音記号を描画」するところまで、進めることにしました。
   色々と異なる項目があるのですが、BASIC文法上の違い以外で、思いつく点は以下の、2点です。
    @ 画面解像度の違い
       ・N88-BASIC
        640x200dot(512色中8色)モードを使用
       ・KM-BASIC
       ワイド・グラフィックモードの、384x216dot(256色同時表示)を使おうと考えました。
       X方向の解像度が約半分以下なので、5線の最後までに入力出来る音符数は当然少なくなります。
        尚、テキストは、X方向=48文字x Y方向=27文字です。
    A 再生方式の違い(音楽記述言語の違い)
       暫くは、音出し無しで、ソフトを考えるので、今は関係ありませんが・・・
       ・N88-BASIC
        MML記述を使用
       ・KM-BASIC
        ABC記述準拠


■ 2019.1.14〜 2019.1.15
 
 ・第1弾:「五線に、ト音記号を描画」
   各音楽キャラクタを、グラフィック描画する場合、その各画素の描画データ(座標データ)を用意しておいて、
   そのデータを読込ながら、その間をラインで結んで(一筆書き)描いて行きます。
   これは、RESTORE〜 READ文で、記述します。その考えは両者一緒です。
   問題は、そのキャラクタを、音程に合わせて、指定位置へ描画しなければならないという点です。
   その際、N88-BASICには、表示エリアの指定が出来るステートメント:VIEW (x1,y1)-(x2,y2)があり、
   元データを、そのエリアに移動することにより実現することが出来ましたが、KM-BASICには用意されてない
   ので、
RESTORE〜 READ文で、基本座標データを、読込む毎に、指定位置までのオフセットを加えることにより
   実現しようと考えました。

  ・また、現ト音記号の描画データの、KN=25(ドット描画点:1+ライン描画点:24)では、多少粗いので、数点ドットを追加しました。
   さらにバランスが多少悪いので、1ドット削除しました。



  ・このような考えで、第1弾:「DRAW_TON.BAS」は、何とか動きました。

  ・第2弾:「五線に、ト音記号+拍子+調性+テンポを、描画」
   以下のような、簡単な仕様
    @ 1ライン5線譜のみにする。
    A 拍子は、4/4のみにし、ト音記号の横に、'C'(一筆書きグラフィック文字)を描画する。
    B 調性(KEY)は、C:ハ長調のみにし、"in C"とプリントする。
    C テンポ表示は、100bpmに固定し、テンポ表示用の小さな、4分音符と共に、"♩=100"と描画する。

  ・オタマジャクシの玉を黒く塗りつぶすのに、N88-BASINでは、PAINT文が使えたが、KM-BASICには無いので
   ドットデータを増やして対応することにした。

   このような考えで、第2弾:「D_MUSI_S.BAS」も、何とか動きました。 


■ 2019.1.16
 
 ・第3弾:「KM-BASICの、サウンド関係を、試してみる」
   今は、再生することは無視しているが、今後のことを考えて、KM-BASICの、サウンド関係を、試してみる。

  ・KM-BASICでは、WAVEファイルの再生もM可能だが、今回は使わない。
   音階を文字列で表現し、BGMを再生するUSIC命令が用意されている。
   音楽記述言語として、ABC記述法に準拠した言語表現により、音楽データ文字列:x$を、記述し、
   MUSIC x$で、BGMを再生することが出来るので、MMLの替わりに使うことにする。
   これを試してみる。

  ・MUSIC x$と、ABC記述法について調べてみました。
   @ MUSIC x$
     x$で表現されるBGMを演奏します。

    ・MUSIC命令では、BGM用のデータを文字列で指定します。文字列の書式は、ABC記譜法に準拠して
     います。ただし、すべての記法が使えるわけではありません。
     なお、キーや速度などのデフォルト設定値は以下の通りです。
      Q: 1/4=90→ 四分音符を、一拍として、I分間に、90打つテンポ指定
      L: 1/8→   1文字の長さを8分音符とすることを表す。最小分解能だと考える。
      K: C→    調性:ハ長調

    ・BGM演奏時に一度に設定できる音の数は、31までです。
     これを超えて音楽を再生したい場合は、
     MUSIC()関数の戻り値を調べ、その値が十分小さくなってから、次のMUSIC命令を実行するよう
     にします。

    <ABC記譜法について:Wikipediaより>
     ● 記譜例
        X:1
        T:sooranbushi
        M:2/4→ 4分の2拍子であることを表す。[他例] M:6/8は、拍子(meter)を表し、この場合は8分の6拍子。
        L:1/8→ 1文字の長さを8分音符とすることを表す。
        K:F→  調がヘ長調(Fメジャー)であることを示す。
        C2 DF | A2 GF | A2 GF | G2 FC | D2 FC | D2 D2 | z2 z2 ||zG AA | GA AA | GA AA | GF D2
        | zA, CA, | CD GF | zG AF | DC FD | D z CC |DF A2| A3 c | G F2 C | D2 D2 | D2 z2||

        ※ 音長・オクターブ等の記述
         ・「CDEFGAB」はそれぞれ「ドレミファソラシ(ドの絶対音高をCとした場合)」。
         ・「z」は休符。
         ・1オクターブ高い音は小文字で、さらにそれより高い音は右上に「'」を付けて表す。
         ・1オクターブ低い音は文字の直後に「,」を打って表す。
         ・各英字の後ろの数字(整数・分数いずれも可)は、音符の長さを示す。
           ex."D2"」=「レの2分音符」(「D1/2」と表記しても可)→ これは、誤記?:レの、4分音符が正しい?

           <以下は自分の考え>
             "C2"=「ドの4分音符」→ ※ 1文字の長さ(音程英字の後ろに数字がない場合)を8分音符としているので
                               8/2=4で、4分音符
         ・「|」は小節の区切り。スペースは意味を成さないが、通常見やすいように一拍を数える箇所に挿入する。


       ※ 音符(note)
         「音高」(pitch)は、「音名」(pitch name)で表す。
          1点ハ(中央ハ)〜1点ロまでは、C D E F G A B のように大文字で書き、
         オクターブ下の音名は、C, D, E, F, G, A, B, のように大文字の後に「 , 」 を付ける。 
         オクターブ上の音名は、c d e f g a b のように小文字で書き、
         2オクターブ上の音名は、c' d' e' f' g' a' b' のように小文字の後に「 ' 」 を付ける。

       ※ 臨時記号(accidental)の、「 # 」は「 ^C 」のように「 ^ 」を、
          「 ♭ 」は「 _C 」のように「 _ 」を、
         ナチュラルは「 =C 」のように「 = 」を音名の前に付ける。

        ※ 「基本音符長」は、拍子によって決まる。
          2/2、4/4、3/4、6/8は、8分音符(1/8)がデフォルト値で、
          2/4、3/8は16分音符(1/16)がデフォルト値である。
          これから分かるように、大部分の拍子では8分音符(1/8)がデフォルト値となる。

          その場合、C8:全音符
          C6:付点2分音符
          C4:2分音符
          C3:付点4分音符
          C2:4分音符
          C3/2:付点8分音符
          C1:8分音符
          C1/2:16分音符
          C1/4:32分音符


      <KM-BASICでの使用例>
       REM Star Trek season 1
       MUSIC "Q:1/4=90"
       MUSIC "L:1/24"
       MUSIC "K:C"

       MUSIC "G,6F9E3D2C2B,zB,_5zB,_6B,_12"
       GOSUB WAITM
       MUSIC "G,6G9F3E2D2C2B,5zB,6B,9B,_3"
       GOSUB WAITM
       MUSIC "A,9B,3C3D3E2F2E2G12B_9A3"
       GOSUB WAITM
       MUSIC "G6F,6z3A,4F4A4c12"
       END

       LABEL WAITM
       WHILE MUSIC()>1
       WEND
       RETURN

   A MUSIC()
      MUSIC命令で演奏中のBGMの残りの音の数を返します。


■ 2019.1.17
 
 ・4オクターブ+5オクターブの、C音までの、Cスケールの、ソースを書いて試してみた。
   音長は、4分・8分・16分で試した。
   鳴らした、各音域の、音は以下の通りです。(最終的に半音は上手く行かず除きました。)
    第1オクターブ:C3〜 B3
    第2オクターブ:C4〜 B4   ※ C4=MIDDLE C
    第3オクターブ:C5〜 B5
    第4オクターブ:C6〜 B6
    第5オクターブ:C7

   ソース名:「MUSC_TST.BAS」とした。

   <気が付いた事(思うように行かなかった事)>
    @ 音長指定の記述に、本家の、ABC記述法と、違いがあるのか、上手く行かない。
       コンパイル・エラーが発生する。
       エラーメッセージは、以下の写真のような感じで、何やらメモリ関係のエラーぽいが?

      これに対し、色々試してみた。
      1つのプログラムの、BGMで、一度に設定出来る、音の数は、31と規定されている。
      試しに、リミットの31個まで、音符を設定して、BGMが鳴るか?
      → これは、OK
         さらに+1して、32個にすると、コンパイルは通るが、音が鳴らなくなる?
      → GOSUB WAITM で、残り音符数が、1になるまで待ってから演奏すると鳴った。
      → どこに入れるか、色々考えるのは、煩わしいので、適当な区切りの、BGMの前に入れる様にする。
      → これで、4分、8分のスケールまでは、OKになったが(8分の最高音"c''"までOK)
         16分に移行したところで、エラーメッセージ発生
      → 単純に、
         L=1/8で、
         GOTO TEST

         LABEL TEST
         GOSUB WAITM
         MUSIC "C/"       REM C/= C1/2 -> 16BU
         END

         で実行しても、同エラー発生
      → L=1/8→ L=1/16 に修正し、MUSIC "C/"→ MUSIC "C"に、修正したら、上手く行った。
         KM-BASICには、C/の記述は無いのかも?→ 文法エラーでなく、メモリー関係のエラー発生

    A 半音を入れると上手く行かない?
       半音を入れると、前に入力したナチュラル・スケールの音程が影響して、音程が、おかしくなる?
       KM-BASICは、半音に対応して無いのかも?

    B 音域により、一部の音程が低くなる。(今回の移植では、C4〜B5までしか使わないので問題無いが・・)
       第1オクターブ:C3〜 B3             C3,D3が低目
       第2オクターブ:C4〜 B4   ※ C4=MIDDLE C OK
       第3オクターブ:C5〜 B5              OK
       第4オクターブ:C6〜 B6                          B6が低目
       第5オクターブ:C7                 OK


■ 2019.1.19〜 2019.1.22
  ・第4弾:「メイン・メニュー画面を作ってみる_1」
   冒頭部には、下向き8分・16分音符及び、上向き8分・16分音符を描画する。
   N88版は、漢字タイトルだが、KM-BASICは、未だ十分な漢字対応が出来てないようなので、
   (表現可能な文字種が制限されている。)、キャラクタ文字で表示することにした。
   まずは、冒頭一行目の、メインタイトル描画までとする。
   
   ソース名:「MM_TITL.BAS」
   割と順調に作業が進んで、上手く行く。
   以下に、音符のドットパターン資料と、表示結果を示した。

  ・第5弾:「メイン・メニュー画面を作ってみる_2」
   第4弾に、各処理項目表示と、問合せを追加。
   今のところは、1...INPUT NOTE が選択されたら、
   
第2弾:でやった、五線に、ト音記号+拍子+調性+テンポを描画まで実行し、ENDのみの処理にしておく。
   他の処理が選択されたら、それぞれの、処理項目を、そのままプリントして、ENDとした。
   これも特に問題なく上手く行く。



■ 2019.2.5
  ・第6弾としては、再生は無視して、とりあえず、5線上に、入力された音符が置ける状態までを
   計画中です。
   このプロジェクトは、なんとなく長くなりそうなので、他の実験テーマをやりつつ、気長に追試
   してゆこうと考えています。


---<ここから、追試:「第6弾:「簡易版の、音符入力処理・描画」の記事>-------------------------------------

■ 2019.2.6
  ・第6弾:「簡易版の、音符入力処理・描画」計画
   (1) 目標
     ・とにかく、簡易的に、音符入力・描画が出来るところまでが、目標。

   (2) 仕様概要
      @ 1声譜・1ラインの、5線のみにする。
      A 拍子は、2/4,3/4,4/4を入力出来るようにする。
      B 調性は、ハ長調のみにするが、一応問合せ入力は作っておく。
      C テンポは、100固定でなく、入力出来るようにする。
      D 音長は、4分・8分・16分の、3種類のみにする。
      E まだ、再生は考えなくて良い。
      F 音符データの保存も考えなくて良い。

   (3) 音符入力処理の、流れ概要(当初の考えとは少し変えました。)
      @ S=1の場合、音符入力処理ルーチンへジャンプ
      A まず、1ラインの、5線と、ト音記号のみ描画

      B 5線譜の下に、"*** INPUT MODE ***"と表示
      C 改行したカーソル位置に、テンポ入力問合せメッセージ表示→ TP$に入力
      D 入力された、テンポ値を、4分音符と共に、表示

      E 改行したカーソル位置に、キー入力問合せメッセージ表示→ K$に入力
      F 入力された、キーを、テンポ表示の上に、"in C"表示

      G 改行したカーソル位置に、拍子入力問合せメッセージ表示→ T$に入力
      H 入力された、拍子を、5線上に表示

    ※ 最初の目標として、まずは、ここまで書いて、動かし、感触を見てみる。


■ 2019.2.7
  ・デバッグ開始
   数点、N88-BASICと、KM-BASICでの、文法上の差異があり、修正した。
    @ IF T$="4" で、Syntax Error
       どうも、IF文の条件式に、文字列は、使えないようだ。
       VAL(T$)=4 で、エラークリア
    A IF K$<>"C"で、Sntax Error
       <>は、N88-BASIC独自の表現。
       KM-BASICでは、C言語と同じ、!=が使える。
       後、IF文の条件式では、文字列同志の比較は出来ないようだ。
       数値に限定される。
       しかし、VAL(K$) != 66("C"=0x42=66)とやっても、VAL(K$)の戻り値は、0になってしまうので、NG
       VALで扱えるのも、数値の文字列に限定されるようだ。
       文字列同志の比較をする場合、STRNCMP(X$,Y$,Z)が用意されていた。
       X$と、Y$を、Z文字数分比較する。等しい場合、0を返す。
       A=STRNCMP("C",K$,1)
       IF A != 0 THEN REM K$ != "C"-> A=1
        GOTO KyKeyI REM Invalid Input Goto Loop
       ENDIF
       と修正し、OKになる。
    B USEVAR TP$
       2文字以上の変数名なので、USEVARで定義したが、どうも、数値と文字の区別は、必要ないようだ。
       (取説に、「ここでは、型の種類は指定しない」とあった。)
    C 見易くしようと思って、
       IF VAL(T$)=4 THEN
        GOSUB ・・・
       としたが、こういう書き方は、エラーになる。
       1行に書くか、THENで、改行は、OKだが、こうした場合、末尾に、ENDIFが必要になる。
       IF VAL(T$)=4 THEN
                         GOSUB ・・・
       ENDIF
       これでOK。
    D K$=INPUT$(Aと同じケース)
       VAL(K$)として、"C"を入力すると、0x42(66)を、返すと考えたが、0が返ってきた。
       VALで扱える、文字列は、10進数に限定されるようだ。
       文字列どうしの比較をする場合、STRNCMP(X$,Y$,Z)が用意されていた。
       X$と、Y$を、Z文字数分比較する。等しい場合、0を返す。

    ※ これらの修正で、第一目標は達せられた。

 

  ・後は、D 音長は、4分・8分・16分(休符は含まず)の、3種類のみに限定して、音符入力・描画が
   出来れば、第6弾の、最終目標が達せられる。
   音符パラメータ入力のところを、追加するのだが、ABC記譜法を意識して記述していかなければ、いけない。
  ・MML記譜法を、ABC記譜法に変えないといけない。
   拍子は、4分音符=1拍とした、4/4・3/4・2/4に限定したので、
   ABC記譜法の、基本音符長単位=Lは、L=1/4固定で考えればよいと思う。(再生は今のところ考えない)
   そうした場合の、音長の表示記述は、以下の通りである。→ 音程+音長で、一組のコマンドを構成する。
   以下は、ハ長調の例を示す。

※ L=1/4固定で考えた場合
音域          スケール            MUSIC A$                                            備考
---------------+-----------+-----------------------------------------+------------------------------------------------------
第3オクターブ    C3-B3     "C,D,E,F,G,A,B,"                                    4分音符の場合
第4オクターブ    C4-B4    "CDEFGAB" C4=中央ド 
第5オクターブ    C5-B5    "cdefgab"
第6オクターブ         C6-B6  "c'd'e'f'g'a'b'"
第7オクターブ           C7-B7      "c''d''e''f''g''a''b''"

第3オクターブ    C3-B3     "C,/D,/E,/F,/G,/A,/B,/"                       8分音符の場合
第4オクターブ    C4-B4     "C/D/E/F/G/A/B/"                             C/は、C1/2の省略形 
第5オクターブ          C5-B5  "c/d/e/f/g/a/b/"
第6オクターブ          C6-B6  "c'/d'/e'/f'/g'/a'/b'/"        190309 "b'"から修正
第7オクターブ          C7-B7     "c''/d''/e''/f''/g''/a''/b''/"

第3オクターブ            C3-B3     "C,//D,//E,//F,//G,//A,//B,//"             16分音符の場合
第4オクターブ            C4-B4     "C//D//E//F//G//A//B//"              C//は、C1/4の省略形/  190310 "E/F/G/A/B/"から修正
第5オクターブ            C5-B5  "c//d//e//f//g//a//b//"
第6オクターブ            C6-B6  "c'//d'//e'//f'//g'//a'//b'//"        190309 "*'/"から修正及び、"b'"から修正
第7オクターブ            C7-B7     "c''//d''//e''//f''//g''//a''//b''//"


■ 2019.2.9
  ・再生は今のところ考えない。
   これは、MUSIC x$ ステートメントを試した時、一部の音域で、音程が低くなる現象が
   起きていて、その原因が解らず仕舞いになっていることが理由だ。
   ところが、今日、その時作成した、MUSI_TST.BASを、再度、RUNさせてみたところ、何故か
   別段問題なく再生出来た。
   ソフトでなく、外的なハード要因が原因と思われる?
   今日は、とても寒い。東京でも小雪が朝、舞っていた。周囲温度の関係で、クロック周波数が変動?(そんな訳ないか?) 


■ 2019.2.11
  ・音符入力時の、パラメータ問合わせ記述をどうするか?
   ABC記譜法では、オクターブを表現するのに、音程部の、ABC文字を、大文字にするか、小文字にするか
   と、さらに続けて、,(1-Oct下)'(1-Oct上) ''(2-Oct上) と、マルチプルに表現しているので
   これを、音符入力時の、パラメータ問合わせの時に、入力させるのは、複雑過ぎて良くない。

   音符入力時の、パラメータ問合わせ記述は、単純・明解な、MML記述(O,L,T等)にし、
   再生の時に、ABC記述に変換しようと思う。
   つまり、再生を考えなければ、今迄通リの記述で良いことになる。

  まずは、簡単仕様にするため、加線が必要な、音符は入力対象外にする。
   対象になる、音域と音は、O4-c〜O5-fに限定する。
   ある程度、書いて、コンパイルし動かしながら、拡張して行く予定。


■ 2019.2.12
  ・デバッグ開始
   FOR IN=IH TO IEで、Syntax Error
   INが、USERVARで、定義されていなかった。
   ところが、USEVAR INとしても、エラーは相変わらず。
   INは駄目なようで(何故かは不明だが、よくある話としては、INはシステムでの、予約語?)
   InVolにしたら、OKになった。
   この修正で、コンパイルは、一通リ通った。


■ 2019.2.13
  ・音符描画位置だが、指定位置に描画したいのだが、思うように行かない音符がある。
   そこで今一度、音符描画位置指定について自分の考えを整理してみた。
    @ 上向き音符(玉が上で、棒が下)の場合
       ベースになる描画データの、一筆書き開始点:(0,14)〜全てのデータに対して、Xofs,Yosfの、
       オフセットを加算することによって希望位置に移動描画する。
    A 
下向き音符(玉が下で、棒が上)の場合
       ベースになる描画データの、一筆書き開始点:(8,0)〜全てのデータに対して、Xofs,Yosfの、
       オフセットを加算することによって希望位置に移動描画する。
  ・上記の考えで、Yofsの値を修正で、上手く行く。(オクターブ・音程と、描画位置が一致した。)
  ・実際に描画してみて、高域の限界は、ディスプレイの関係で、O6-"a"で、Y1=0になり限界と、判った。
   また、4分音符で置くと、1ライン(1声5線譜上段)には、4*4=16個入ることが確認できた。(未だ加線描画は考えていません。)

   尚、小節線は、拍数を計算しながら、自動描画しているが、一部の条件下では未だ上手く行っていない。


■ 2019.2.14
  ・昨日終盤の、8分音符か、16分音符で、スケールを入力して行った場合、小節線が表示されない問題解決した。
   それぞれの、デュレーション(音価)判定後に、LT(トータル)していって、それが、拍子の分子(VALTM$))と
   等しくなったら、小節線を引くように直したが、入力を終えていざ音符描画する段階で、メモリ関係と思われ
   エラーが発生し、ハード・リセットを要求してくる。
   <問題点と対策>
    デュレーション変数名を、Tとしていたが、これは、他で使っている文字変数:T$と重複する。
    同じ英文字で、文字変数を、数値変数として使うのは駄目なようだ。
    T→ Dに修正したら、OKになる。

  ・次は、加線描画をやってみる。
   音域によって、座標をかえてやらないといけないので、面倒だが、何とか出来た。
  ・3/4・2/4拍子で、4分・8分・16分混合にしても、小節線描画OKを、確認。 

 


■ 2019.2.15
  ・1ライン(1声5線譜上段)に、入力出来る音符数は、おおよそ、16個なので、16個を、リミットにする。
   17個目の入力は無視して、入力を強制終了し、"INPUT END"と表示後、"0"キーが押されるまで待ち、
   押されたら、メインメニューに戻るようにした。
   この16個のリミットは、FOR InVol=IH TO IE〜 NEXTループを抜けたことによって簡単に判断している。

  ・音符パラメータ(Tone・Length・Octerve)の入力が済んだら、直ぐに、音符描画するのではなく、
   "Is this airight ?"(これで、よろしいですか?)と表示して、"y"入力だったら、音符描画、"n"だったら
   Toneに戻って、修正(再入力)出来るようにしました。
   但し、確定後の修正までは、今のところ考えていません。

  ※ これで、ソース名:「MM_SUM2.BAS」:第6弾_(簡易版の、音符入力処理・描画)の、完成としたい。
     実験風景と、各種音符描画の写真は、このページトップの写真を参照してください。
  ※ 第7弾としては、これに、音符を置いた時に、その音符の音を鳴らすのと、16個の入力が済んだ時に
     それまでの音列を曲として再生出来るところまでを、目指したい考えでいます。
     どうなることやら・・・


---<ここから、追試:「第7弾:音出し/ 第8弾:SDへのSAVE/ 第9弾:音符データ呼出し」の記事>-------------------------------------

■ 2019.3.7
  ・
第7弾:音出し検討_MUS_SUM3.BAS
    @ 拍子は、4分音符=1拍とした、4/4・3/4・2/4に限定したので、ABC記譜法の、
       基本音符長単位=Lは、L=1/4固定で考えればよいと思う。
    A 入力時の、音符パラメータ・コマンドの整理
      ・音長
       L:4,8,16限定
      ・オクターブ
       O:3〜6限定(上限:O6-a)
      ・音程
       T$:'c' 'd' 'e' 'f' 'g' 'a' 'b'(半音なし)
    B まずは、音符を五線上に置いた時に、音を出すのみにした場合は、以下のような記述の流れになるだろう。

※ 曲全体パラメータ・音符パラメータ入力処理部抜粋

REM /////////// Note Factor Input ///////////////////
X1=50 REM Init Note Xpoint
CURSOR 0,7:PRINT "*** INPUT MODE ****"

REM --------- Input tempo -------------------
LABEL TpKeyI
CURSOR 0,9:PRINT "Tempo"
CURSOR 6,9:TP$=INPUT$()
IF VAL(TP$)<32 OR VAL(TP$)>255 THEN
GOTO TpKeyI REM Invalid Input Goto Loop
ENDIF

REM PRINT NOTE 4 BY TEMPO 
REM KN=11
KN=8
RESTORE TMPDAT
X=4:Y=0
GOSUB WRONE,7,8

REM PRINT TEMPO
CURSOR 2,1:PRINT "= ";TP$

REM --------- Input key ---------------------
LABEL KyKeyI
CURSOR 0,10:PRINT "Key"
CURSOR 6,10:K$=INPUT$()

A=STRNCMP("C",K$,1)
IF A != 0 THEN REM K$ != "C"-> A=1
GOTO KyKeyI REM Invalid Input Goto Loop
ENDIF

REM PRINT KEY
CURSOR 1,0:PRINT "in ";K$

REM --------- Input time --------------------
LABEL TiKeyI
CURSOR 0,11:PRINT "Time"
CURSOR 6,11:TM$=INPUT$()
IF VAL(TM$)<2 OR VAL(TM$)>4 THEN
GOTO TiKeyI REM Invalid Input Goto Loop
ENDIF

REM Draw time
GOSUB Dhyosi

REM ===================================================

REM --------- Input Tone.Oct.Length ---------
FOR InVol=IH TO IE
LABEL Tone
CURSOR 0,13:PRINT "Tone"
CURSOR 8,13:T$=INPUT$()

LABEL LenIn
CURSOR 0,14:PRINT "Length"
CURSOR 8,14:L$=INPUT$()
IF VAL(L$)=0 OR VAL(L$)>64 THEN
GOTO LenIn REM Invalid Input Goto Loop
ENDIF

LABEL OctIn
CURSOR 0,15:PRINT "Octerve"
CURSOR 8,15:O$=INPUT$()
IF VAL(O$)<3 OR VAL(O$)>6 THEN
GOTO OctIn REM Invalid Input Goto Loop
ENDIF

GOSUB GenTon /// ここに音出し追加

///===================================================================================

※ 1音の音出しサブルーチン検討

REM ======== Generate Tone (one note) =============
LABEL GenTon
REM --------- Set ABC Data -------------------
IF VAL(O$)=3 THEN
GOSUB CnvBig
IF VAL(L$)=4 THEN ABC$=T$+","
IF VAL(L$)=8 THEN ABC$=T$+"./"
IF VAL(L$)=16 THEN ABC$=T$+".//"
ENDIF

IF VAL(O$)=4 THEN
GOSUB CnvBig
IF VAL(L$)=4 THEN ABC$=T$
IF VAL(L$)=8 THEN ABC$=T$+"/"
IF VAL(L$)=16 THEN ABC$=T$+"//"
ENDIF

IF VAL(O$)=5 THEN
IF VAL(L$)=4 THEN ABC$=T$
IF VAL(L$)=8 THEN ABC$=T$+"/"
IF VAL(L$)=16 THEN ABC$=T$+"'/"
ENDIF

IF VAL(O$)=6 THEN
IF VAL(L$)=4 THEN ABC$=T$+"'"
IF VAL(L$)=8 THEN ABC$=T$+"'/"
IF VAL(L$)=16 THEN ABC$=T$+"'//"
ENDIF

REM --------- Generate Tone (one note) ---------
GOSUB GenTon

RETURN

REM -------- Generate Tone ------------------
LABEL GenTon
REM MUSIC "Q:1/4="+TP$ REM Set Tempo
REM MUSIC "K:C" REM Const "C"

MUSIC "L:1/4"
MUSIC ABC$
RETURN

REM -------- Converto Big Letter ------------
LABELCnvBig
IF T$="c"THEN T$="C"
IF T$="d"THEN T$="D"
IF T$="e"THEN T$="E"
IF T$="f"THEN T$="F"
IF T$="g"THEN T$="G"
IF T$="a"THEN T$="A"
IF T$="b"THEN T$="B"
RETURN


■ 2019.3.10
  ・MUS_SUM3.BASデバッグ開始
   8分・16分音符入力時に、メモリ関係の、"Bus load/store error"発生
   → どうも、ABC記述に於いて、省略形は使えないようだ。
     音価を示す省略形は、例えば、ドの8分音符は、C/、16分音符は、C//だが、C1/2、C1/4
     としないと駄目。修正で上手く行く!!
     この修正のみで、全音域で、音符を置いた時、音が鳴ることを確認した。


■ 2019.3.11
  ・次は、1Line五線譜に,、MAX16個の音符入力が完了した時点での、BGM再生を考えてみる。
   KM-BASICの、MUSIC文のBGM演奏時に、一度に設定出来る音の数は、31までなので、
       適時入れる、WAITは必要ないと考える。

  ・1音の音出しの時に、ABC$に、入力音符パラメータを格納している。
   これとは別に、BGMabc$という変数を用意し、BGMabc$=BGMabc$+ABC$ として加算して行く。


■ 2019.3.12
  ・昨日、一応、BGM再生も出来た。
   だが、若干問題が・・・ 今日は、これを追求。

      何故か、8分で音符を置いていった時、7個入力したところで、メモリ不足エラーが起きた。
   "Not enough memory" In line 567 T$=INPUT$
   現在、切の良いところで、4分音符で4小節分の、音符数=16個、置けるようにしたかったので
   グラフィック・モードを、ワイド:384x216ドット 256色に設定している。
   これだと、メモリを、81Kbyte占有してしまう。
   音符数の上限は減る(16個→12個)が、標準:288x216ドット  256色(61Kbyte占有)に変更することにした。

   これで、メモリ不足エラーは出なくなり、BGMも再生出来るようになった。


■ 2019.3.13
  ・第8弾_MUS_SUM4(SDへのSAVE追加)検討
   大まかに、SAVEのために何が必要か、列記してみた。
    @ REPLAYメッセージに、's'(save)入力の選択枝追加
       "One more play...(y/n/s) "
    A 's'入力の場合の処理追加
    B SaveSDサブルーチン追加
      ・まず、曲全体に係わるパラメータ、3個(TP$(テンポ)/K$(キー)/TM$(拍子))を
       ファイルに書込む。
      ・次に、BGM音符データを、append(追加書込み)する。


■ 2019.3.14〜 2019.3.15
  ・本番の、ファイル書込みプログラムを組む前に、KM-BASICでの、ファイル操作に係わる、短い
   テスト・プログラムを書き、挙動を確認してみる。→ FILE_TST.BAS
    (1) テスト仕様
      @ 曲のデータ(文字列と、整数)を書込む。
        (ここでは、文字列の他、IE(整数):総音符数-1)も含みました。またキーは、KY$としてます。)
         
TP$="120"
         KY$="C"
         TM$="4"
         IE=11
         BGMabc$="CDEFGAB"

      A 書込み後、それを読出し、PRINT文で液晶ディスプレイに表示し確認してみる。

    (2) 結果→ okだった。

       FPRINT文の、各パラメータ区切りに、何(',' or ';' )を使うかで悩んだが、';'でokだった。
       また、整数の書込み・読込みに、どんなステートメントを使うかで悩んだが、
       書込みは、FPUTC IE・読込みは、I=FGETC()でokだった。


■ 2019.3.16〜 2019.3.17
  ・昨日の結果を踏まえ、第8弾_MUS_SUM4(SDへのSAVE追加)へ戻る。
   SAVEされたSDを、バイナリ・エディタの、ダンプリストで確認するところまで試してみる。
   これも上手く行く。


■ 2019.3.18
  ・第9弾_MUS_SUM5(音符データ呼び出し追加)検討
   今回は、音符データを、1個ずつ呼び出して、その都度、音符表示し(置いた時の音は不要)
   12個揃ったところで、BGM演奏するだけの処理とする。
   これを実現する為には、メニュー1:音符入力時の、音出し用の、BGMabc$とは別に、音符入力している時に
   1音ずつ音符表示する為の配列が必要になる。

   O$(11)・T$(11)・L$(11)
   (※ 注意: この後のデバッグで気が付い事だが、KM-BASICでは、文字列配列は使えないようで、
           数値配列に修正し、後で、文字に変換して対処した。詳細は後述します。        )

   尚、配列の最大要素数は、以下のように決めた。
   第6オクターブ:C-Aで16分音符が、12個並んだ時が最大なので、1音で、最大4byte必要
   12個@1ラインMAXなので、4x12=48byte=384bit必要
   KM-BASICの配列の括弧の中に入れる要素数は、C言語とは異なり、総数-1のようなので、それに従う。
   PIC32の変数は、32bitなので、総数=384/32=12となり、括弧の中に入れる数値は、11になる。

   各配列(オクターブ・音程・音長)に、各音符パラメータ入力データを格納し、これも含めて、SDにセーブする
   必要がある。


■ 2019.3.19
  ・配列名に、bufを追加して、次のように宣言したが、どうしても、エラーになる。  
   DIM Tbuf$(11)
   DIM Lbuf$(11) 
   DIM Obuf$(11) 
   どうも、KM-BASICでは、文字列の配列は使えないようである。
   そういう例が、マニュアルに見当たらなかった。  例があったのは、DIM A(10)と、DIM A#(10) だけであった。


■ 2019.3.20
  ・
文字列の配列は、使えないので、入力された、文字列パラメータを、整数値に変換してから、
     配列に格納することにした。

REM --------- Input Tone.Oct.Length ---------

REM FOR InVol=IH TO IE

FOR InVol=0 TO 11

 LABEL Tone

 CURSOR 0,13:PRINT "Tone"

 CURSOR 8,13:T$=INPUT$()

 

 LABEL LenIn

 CURSOR 0,14:PRINT "Length"

 CURSOR 8,14:L$=INPUT$()

 IF VAL(L$)=0 OR VAL(L$)>64 THEN

  GOTO LenIn  REM Invalid Input Goto Loop

 ENDIF

 

 LABEL OctIn

 CURSOR 0,15:PRINT "Octerve"

 CURSOR 8,15:O$=INPUT$()

 IF VAL(O$)<3 OR VAL(O$)>6 THEN

  GOTO OctIn  REM Invalid Input Goto Loop

 ENDIF

 

 REM One note data bufferring(SEISUU)

 Tbuf(InVol)=ASC(T$)

 Lbuf(InVol)=VAL(L$)

 Obuf(InVol)=VAL(O$)

     ・

     ・

     ・


■ 2019.3.21
  ・
MUS_SUM5.BAS デバッグ続行
   <現状:昨日の状態>
     @ Note Saveは、表面上、上手く行っている模様
     A 
Noe LoadRead)して、楽譜表示するが、まともな表示にならない。
       
5線・ト音記号・拍子・小節線は出るが、音符が出ない。(何故か中央Cの位置に加線が出るだけ)

   <調査>
     @ Note Saveされた、「SCALE_C.TXT」を、バイナリ・エディタの、ダンプリストで確認してみた。
        下図の通リ、Saveは、OKだった。しかし、Loadは、NG

       (ファイル名の頭に、3_が付いていますが後で整理のために追加しただけで内容は同じです。)

 

 

    A デバッグを進めて行く内に、LoadSDサブルーチンの、
       TP$=FINPUT$(LEN(TP$))を実行した瞬間に、"Bus load/Store Error"で止まってしまい、
       RESET ONを要求してきた。

       TP$(テンポ)は可変長なので、LEN(TP$)として、戻り値を引数として入れているが、ここを
       3に固定(今は、120にしている)すると、このエラーは出なくなった。

 

       よくよく考えると、P_ONして、いきなりメニューから、「音符呼び出し」を選んだ場合、

       TP$は何も入力されてない状態なので、LEN(TP$)としても無意味である。
       音符入力時に、LEN(TP$)として、これを、SaveSD時に、セーブしておく必要がある。

       とりあえずは、3の固定値で、デバッグを進めることにした。

■ 2019.3.22
  ・MUS_SUM5.BAS デバッグ続行
   音符呼出し処理で、音を置いて行く毎に音を鳴らしても描画の方が速いので、描画が終わってから
   連続再生のように聞こえる。
   音符間に、遅延を入れてもよいだろうが、あまり意味が無いので止めた。
   リード終了後に、自動連続再生するので必要ない。
   これで、TP#長3固定のバージョンは、OKになる。

  ・次に、TP$可変長版を検討。
   以下も上手く行く。
    @ 音符入力時の、TP$の時、S=LEN(TP$)として
    A SaveSDの時、Sを保存
    B LoadSDの時、Sをロード

  ・メインメニューの、2AUTO PLAYは、必要ないので削除しました。
   メニュー3READ NOTE DATAが、それに相当します。

  ※ これで、妥協点はあるが、MUS_SUM5.BASの完了とします。


<最終ソース>
 ・こちらから、どうぞ

  第1弾:「五線に、ト音記号を描画」:DRAW_TON.BAS
  
第2弾:「五線に、ト音記号+拍子+調性+テンポを、描画」:D_MUSI_S.BAS
  
第3弾:「KM-BASICの、サウンド関係を、試してみる」:MUSC_TST.BAS
   第4弾:「メイン・メニュー画面を作ってみる_1」:MM_TITL.B
   第5弾:「メイン・メニュー画面を作ってみる_2」:MM_SUMI.BAS
   第6弾:「
簡易版の、音符入力処理・描画」:MUS_SUM2.BAS
   第7弾:「音出し追加」:MUS_SUM3.BAS
   第8弾:「SDへのSAVE追加」:MUS_SUM4.BAS
   第9弾:「
音符データ呼出し追加」:MUS_SUM5.BAS


← 実験テーマ1に戻る   TOP PAGEに戻る   実験テーマ114へ →