X68000エミュレータでWindowsのソフトウエアMIDIを使ってみる
使うもの
② VirtualMIDISynth MIDIドライバ
と
SGM-V2.0.1.sf2 サウンドフォント
導入については↓こちらがわかりやすいです
③ ZMUSIC ver2 X68000用音源ドライバ+BASIC&C言語用ライブラリ
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メッセージについては詳しく解説してくれるページがたくさんありました
音楽用語がわからなくて、自分は音を出すところまでしかできませんでしたが…
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音配列のようです。
変更の仕方についてはこちらに詳しい開設があります
一応、書いてえきます
実機の場合ローマ字入力は「shift」キーを押しながら「かな」キーを押すとローマ字入力になります。
MSXWEBでは
「shift」キーと「右alt」キー…ということになります。
「かな入力」の人はあまり多くないと思いますが
自分はカナ入力なので直さないといけません(^^;
この変更はキー操作ではなくプログラム的(ワークエリアの書き換え)で行いまい
50音配列にしたい場合は
POKE &HFCAD,0
JIS配列にする場合
POKE &HFCAD,1 ( 0以外を書き込む )
毎回設定するのは不便ですからautoexec.basで自動で設定できるようにしてしまいます。
WEBMSXの起動パラメータについて
これでいいのかしら?
ブラウザ上で動く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言語は「若いころ、ちょっといじったことがある」程度なのでほぼど素人であります
↑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という名前に変更したら使えると思います