X68000エミュレータでWindowsのソフトウエアMIDIを使ってみる

使うもの

⓵ XM6TypeG             X68000エミュレータ

retropc.net

 

② VirtualMIDISynth    MIDIドライバ

  と

  SGM-V2.0.1.sf2     サウンドフォント

 

導入については↓こちらがわかりやすいです

umetake.d.dooo.jp

 

③ ZMUSIC ver2    X68000用音源ドライバ+BASIC&C言語用ライブラリ

retropc.net

 

XM6typeGの使い方から書いていると大変なことになるので、「動いている」という前提で…

 

まずZMISICを常駐させます

ZMUSIC[リターン]でOKです

 

X-BASICで使うのでBASIC.CNFファイルを編集

この辺はX68000を使ったことがある方は大丈夫かと思います。

このへんはX-BASICのマニュアルとZ-MUSICのマニュアルの方がわかりやいと思います。

XM6rypeGの「ツール」→「MIDI」でMIDIの設定をします。

よくわかっていませんが設定はこんな感じ

VirtualMIDISynthがセットできればOKかと…

リセットコマンドは「GSでいいんじゃないかなぁ」という根拠のない設定

 

X-BASICを起動します。

ZMUSICが使用可能かどうかの確認は

ダイレクトモードから

m_init()

としてエラーが出ないことで確認できると思います

 

さっそくですが

単純に音を出すリストはこんな感じです

音を出すまでがとりあず大変だと思うので、まずはそこまでできるように…

   10 str zz
   20 m_init() 
   30 m_count(192) 
   40 m_alloc(1,10000) 
   50 m_ch("fm") 
   60 m_assign(10,1) 
   80 m_trk(1,"@1 v15 o4 cde")
   90 m_play()
  100 input zz
  

プログラムは

20 音楽関係のデータを初期化して

40 演奏トラックを確保して

50 演奏チャンネルの並びを指定して

60 40で確保した演奏トラックをMIDIのチャンネル0番に指定して

80 演奏トラックに演奏データをMMLで記述して

90 演奏させる

 

という流れです

 

音色が色々変えられます

どんな音色があるかは

VirtualMIDISynth Configurator

で確認できます

サウンドフォントをダブルクリックすると音色リリストが表示されます

コピペできるのでエディターなどに書き写してしまうと楽です

 

データは

バンク:プリセット = 音色名

という順でならんでいます

 

   80 m_trk(1,"@1 v15 o4 cde")

上のプログラムの80行

@1

がプリセットの変更です

注意としては、ZMISICのMMLでは表のプリセット値に+1した値を記述します

 

バンク切り替えは

   80 m_trk(1,"i3 @1 v15 o4 cde")

プリセット変更の前で                       ↑

i(バンク)

で行います、

バンク切り替え、プリセット変更は両方書かないと有効にならないような感じなので

両方一緒にしておいたほうが無難だと思います

 

i(バンク) @(プリセット番号+1)

という感じですね

 

例えばこの表で


2:50 = StackStrings

 

この音を使いたい場合は

i2 @51 v15 o4 ceg

という感じになります

 

 

 

次はMMLを使わず、MIDIに直接データを送って音を出す方法です

プログラムの好きなタイミングで音が出せますので効果音などの用途ならこういうやりかただと思います

 

   10 m_init()
   20 m_ch("fm")
   30 /*
   40 m_out(&HB0,0,3)        :/* SET BANK
   50 m_out(&HC0,126)        :/* SET PRESET
   60 m_out(&H90,40,127)     :/* SOIND ON
   70 for i=0 to 10000:next
   80 m_out(&H80,40,127)     :/* SOUND OFF

 10 音源を初期化して

 20 演奏チャンネルの並びを指定(今回の処理では意味はないです)

 40 バンクを切り替え

  Bn 00 xx

  n は MIDIのチャネル 0~15

  zz は バンク

 50 プリセットを指定

  Cn yy

  n は MIDIのチャンネル

  yy  はプリセット番号(今回は+1しなくてよい)

 60 音を出す

  9n zz vv

  n は MIDIのチャンネル

  zz は音階の番号(ノートナンバーと呼ぶ模様)

  vv は音量(ベロシティと呼称) 0~127で127が音量が大きい

 70 ウエイト

 80 音を消す

  8n zz vv

  n は MIDIのチャンネル

  zz は音階の番号

  vv は音量←この数値は特に意味がない模様

 

データをMIDIに直接送るような操作は「MIDIメッセージ」と呼ばれている模様

16進数のデータを順に送るあたりアセンブラっぽいですね

マイコン少年的には、こういうやりかたりほうが理解しやすかったりします

 

 

MIDIメッセージについては詳しく解説してくれるページがたくさんありました

音楽用語がわからなくて、自分は音を出すところまでしかできませんでしたが…

www2.odn.ne.jp

 

 

WEBMSXの文字入力

キーボードの使い方ゆ各種文字の入力の仕方についての覚書です

 

https://webmsx.org/?MACHINE=MSX2J

日本製MSX2を起動します

自分背景青は見づらいので色を変更します

 

 

そのままキーボードから入力すると英数が入力できます

基本的には今のPCと同様にタイプできるはずです。

 

 

かなの入力をしてみます。

実機だと「かな」キーを押すと英数に変わってかなが表示されます

 

右下の歯車ボタンから「help & setting」を選択し、キーボードの状態を見てみます。

 

 

キーの上にマウスを持っていくと対応するキーを参照できます

かなキーは「CODE」キーとなっています

右側の「alt」キーがかなキーにわりあてられていますので、setting画面を抜けて押してみます

 


ひらがなが入力できるようになりました。

 

次はカタカナです

カタカナを入力したいときは「かな」状態で「CAPS」キーを押します

うちのキーボードの場合Windowsの「caps lock」キーはcapsではなかったです

 

こういう時も先ほどと同様に割り当てられているキーを探します

 

「help & settig」でキーを確認してみます

「無変換キー」等がわりあてられています

 

 

 

無事にカタカナも入力できました。

 


MSXのカナ入力にはみっつの方式が用意されていて

JIS配列

50音配列

ローマ字入力

の3つがあり切り替えられます

それぞれ切りかえられます

 

 

今の入力形式は50音配列のようです。

変更の仕方についてはこちらに詳しい開設があります

msxjpn.jimdofree.com

 

一応、書いてえきます

実機の場合ローマ字入力は「shift」キーを押しながら「かな」キーを押すとローマ字入力になります。

MSXWEBでは

「shift」キーと「右alt」キー…ということになります。

 

 

「かな入力」の人はあまり多くないと思いますが

自分はカナ入力なので直さないといけません(^^;

 

この変更はキー操作ではなくプログラム的(ワークエリアの書き換え)で行いまい

50音配列にしたい場合は

POKE &HFCAD,0

 

JIS配列にする場合

POKE &HFCAD,1   ( 0以外を書き込む )

 

毎回設定するのは不便ですからautoexec.basで自動で設定できるようにしてしまいます。

 

WEBMSXの起動パラメータについて

これでいいのかしら?

 

webmsx.org

ブラウザ上で動くMSXエミュレータですが起動する際にマシン構成を設定することができます

 

ちょっと調べてサンプルを書いてみました

とりあえず動産確認しましたが、自分もよくわかっていないので、自己責任で試してください

 

MSX2+の日本仕様のマシンを起動します
https://webmsx.org/?MACHINE=MSX2PJ

 

上にハードディスクを追加
https://webmsx.org/?MACHINE=MSX2PJ&p=HARDDISK

 

さらにSCCをスロット1に
https://webmsx.org/?MACHINE=MSX2PJ&p=HARDDISK,scc

 

試しに4MBのマッパーRAMを追加
https://webmsx.org/?MACHINE=MSX2PJ&p=HARDDISK,scc,RAM4096

 

パラメータについての詳細な解説は作者様のページから
(ブラウザ翻訳機能を使用すれば理解できると思います)

https://github.com/ppeccin/WebMSX/blob/master/README.md

 

夢のマシンの構成してみてはいかがでしょう?

XC備忘録② BASIC的な文字列操作・変換

文字列の一部を取り出すleft$。mid$、right$は必要頻度は高いと思うが標準的な関数のなかにはなかった。

メモリの転送…みたいな処理で代用するのかな?

XCのBASICのライブラリに関数があったのでそのまま使うことにする。

ネットを検索するとルーチンの作り方がすぐ見つかるけどXCなら関数利用でいいと思う

 

valとstr$もないようだが、valがないとコマンドラインからargvで数値を受け取ったときなど面倒なので必要だと思うんだが見当たらず

valについては、戻り値がdouble型というのが興味深い、X-BASICにはdouble型なんて変数の型はないのに…intで使うことが多いと思うので使う時はキャスト(型変換)までセットで覚えた方がよさそう

 

hex$とbin$は自分はよく使うので一応

 

 

/*BASIC的な文字列操作*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <basic.h>
/*
#include <iocslib.h>
#include <graph.h>
*/

void main(int argc,char *argv[]) {

    char *msg1 = "SHARP X68000XVI";
    char *msg2 = "SONY MSX2 HB-F1XD";
    char *msg3 = "NEC PC-8801mk2model30";
    char aa1[63] = "";
    char aa2[63] = "";
    char aa3[63] = "";
    int d;

    printf("msg1 = %s\n",msg1);
    printf("msg2 = %s\n",msg2);
    printf("msg3 = %s\n",msg3);
    printf("\n");

/* left$ right$ mid$
    ここから先の関数は、代入先にはそこそこの領域が必要
    この手の操作を行うななら、各文字列の領域は40バイト以上取っておく方が無難
*/

    b_leftS(aa1,msg1,5);
    printf("left$(msg1,5) %s\n",aa1);

    b_rightS(aa2,msg2,7);
    printf("rifht$(msg2,7) %s\n",aa2);

    b_midS(aa3,msg3,5,7);
    printf("mid$(msg3,5,7) %s\n",aa3);

/* VAL STR$

valの戻り値はdoubleなので注意

*/

    d= (int) val("3000");
    printf("val(\"3000\") %d\n",d);

    b_striS(aa1,12345);
    printf("str$(12345) %s\n",aa1);

/*    b_strfS():    浮動小数点用
*/

/* HEX$ BIN$
*/
    b_binS(aa1,65535);
    printf("%s\n",aa1);

    b_hexS(aa2,250);
    printf("%s\n",aa2);

/* end
        ↓エラー用exit
        exit(EXIT_FAILURE);
*/
    exit(EXIT_SUCCESS);
}

XC備忘録① 文字列操作

Cでは文字列変数がないので、ポインタというのを使う

C言語のポインタの概念は難しい、国語力が弱くてマジでやばい(^^;

昭和のマイコン少年の自分は特にパソコンの学校にも通ってない完全独学、最新の考え方どころか、お行儀のよいプログラミングの概念知識も持ち合わせていない

ただ昭和BASICとZ80アセンブラは身体で覚えたので、そのあたりの知識で解釈することにする。 

 

文字列…ポインタの宣言・定義は

char *TEXT1="X68000";

と書くのだが

C言語の文字列定義はアセンブラのワークエリア定義のようなものらしく

TEXT1:   DB "X68000",0

という意味な模様

Z80だとこれを

LD HL,TEXT1

と、レジスタにアドレスを代入して操作するけど、Cはラベルのまま使えます…ワークエリアのラベルがCで言うポインタ…なんだと思う…多分

 

で、アドレスに書かれた値の参照はアセンブラだと
LD    A,(TEXT1+n)

こんな感じで参照するが、C言語も同じで

a = TEXT1[n]

という表記になる。ちなみにこれはC言語の配列の書式に等しい

 

別の表現をすると

「ポインタは配列の格納されている領域の先頭アドレス」とも言える

 

 

それで本題の文字列操作

C言語ではBASICみたいに文字列をのほほんと操作できない

例えば

if a$=B$ then print "あたり"

みたいには書けない

そもそも文字列変数がないから、こういう書式はありえない

 

このあたりはアセンブラだと思った方が考えやすいかもしれない

アセンブラ的な考え方だと

文字列の比較は、ワークエリア同士の比較だ

ポインタを一個ずつ動かして、一文字ずつ判定していく処理を繰り返す

 

さすがにそんなことをしていられないので各種関数を利用することにする

 

で、とりあえず作ったもの

/*文字列操作のテスト
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void main(int argc,char *argv[]) {

    char *msg1="X68000";
    char *msg2="XVI";
    char *msg3="compact";
    char *msg4="";
    char *msg5="";
    int i,d;
    int len;

/* peint msg1~3
*/

    printf("msg1 = %s\n",msg1);
    printf("msg2 = %s\n",msg2);
    printf("msg3 = %s\n",msg3);
    printf("msg4,5 = NULL\n");

/* msg4 = msg1
    BASICでいう文字列の代入、ポインタではなく文字列自体のコピー
    strcpy()
*/
    printf("BASICでいう文字列の代入、ポインタではなく文字列自体のコピー\n");

    printf("msg1 = %s\n",msg1);
    printf("msg4 = %s\n",msg4);
    strcpy(msg4,msg1);
    printf("msg1 = %s\n",msg1);
    printf("msg4 = %s\n",msg4);

/*    if msg1 = msg4
    if msg1 = msg2
    文字列の比較
    strcmp(msg1,nsg4);
    ↑いわゆるBASICの文字列比較
    strcmpi(msg1,msg4));
    ↑大文字小文字は区別されない
    等しいときは0を返す
*/

    printf("文字列の比較、等しいときは0を返す\n");

    d = strcmp(msg1,msg4);
    printf("%d\n",d);
    printf("%d\n",strcmp(msg1,msg2));


/* len(msg)
    文字列の長さ
    strlen(msg1)
*/

    printf("文字列の長さ\n");

    len = strlen(msg1);
    printf("strlen(msg1) = %d\n",len);
    printf("strlen(msg2) = %d\n",strlen(msg2));

/* 文字列の足し算

    msg1 = mdg1 + msg2
    strcat(msg1,msg2);
  msg2も内容が壊れる?、msg2のポインタが一個進む?
*/

    printf("文字列の追加、加算\n");

    printf("msg1 = %s\n",msg1);
    printf("msg2 = %s\n",msg2);
    printf("msg1 + msg2 = %s\n",strcat(msg1,msg2));
    printf("msg1 = %s\n",msg1);
    printf("msg2 = %s\n",msg2);

    --msg2;
    printf("--msg2 = %s\n",msg2);

/*
    新しく領域確保…文字列コピーや同じ?
*/

    printf("新しく領域確保…文字列コピーと同じ?\n");

    msg5 = strdup(msg3);
    printf("msg5 = %s\n",msg5);

    printf("各ポインタの内容確認\n");

    printf("msg1 = %s\n",msg1);
    printf("msg2 = %s\n",msg2);
    printf("msg3 = %s\n",msg3);
    printf("msg4 = %s\n",msg4);
    printf("msg5 = %s\n",msg5);

/* end
        ↓エラー用exit
        exit(EXIT_FAILURE);
*/
    exit(EXIT_SUCCESS);

}

 

X68000のGCCの導入について

X68000エミュレータC言語の開発環境を構築する

 

自分はC言語は「若いころ、ちょっといじったことがある」程度なのでほぼど素人であります

retropc.net

SHARP製Cコンパイラ(XC)やGCCなど必要なソフトはこちらで入手できます。

 

今回は

コンパイラはXCではなく広くX68ユーザーに使われているGCC(真理子版)を

ライブラリは手元にマニュアルが残っていて、関数の使い方が確認しやすいXCのライブラリ…という環境を構築しようと思います

 
C言語環境セットアップ

http://www.ausystem.org/~aushacho/sfxvi/kouza/h06_10/1.htm

 

X68000 Programming / X680x0公会堂

 

GCCのドキュメントにもXCのライブラリを使う方法は記載されていますし、ネットで検索をかけると上のようなページがヒットします、こちらは手順がわすりやすく書かれていますので、手順通りにすすめれば構築できるはずですが…大変でした

 

解説サイトもドキュメントも十分親切でわかりやすいのですが

gnulib.l

というファイルがみあたりません

 

LIBC 1.1.32A - ライブラリ - プログラミング - ソフトウェアライブラリ - X68000 LIBRARY

こちらのアーカイブ

libgnu.a

というのはありますが微妙に名前が違います

 

どちらも同じものが含まれるライブラリなのですが書式が違います

そして、使用の際は書式を統一しないといけません

 

サイト等の解説には「.lの方を使ってください」的な記述ですが見当たりません

 

おそらくですが

過去に配布されたライブラリには.aと.lの両方が入っていたものの、現在配布されているものは.aだけ…という状況なのだと思われます。

 

ということで、現代では

libgnu.aからgnulib.lをこさえる作業が必要となります。

 

具体的な手順は

① AR.Xというソフトでibgnu.aの中身を取り出して

② LIB.Xというソフトでgnulib.lをこさえます

AR.XとLIB.Xは、XCコンパイラに同梱されています

AR.X、LIB.Xの使い方はXCの「アセンブラマニュアル」の第7章「アーカイバ」第8章「ライブラリアン」にあります

 

勉強不足でわからないのですが、取り出しやライブラリ作成でワイルドカードが使えなかったので「一個一個とりだして」「一個一個登録」的な作業が必要になります。

 

恐ろしく非効率的作業なので

ar -l libgnu.a > list.txt

パイプでリストをテキスト出力

これを元にエディターで頭の悪いバッチファイルをこさえて変換しました

https://drive.google.com/file/d/1UjMgIoLPc72xp4T28Vrz4nNb3zUTs-Mm/view?usp=sharing

 

出来上がりのファイル名が違っていますが、gnulib.lという名前に変更したら使えると思います