Hatena::ブログ(Diary)

分室の分室 このページをアンテナに追加

2016-05-18 Wed

MSX で We Will Rock You(Queen) やってみた。

【547】


 英ロックバンド Queen。…のフレディ・マーキュリーが没したのは 1991年11月(享年45歳)。今年で没後25年になる。もう四半世紀が経とうとしている。時間は決して止まらず、流れ続ける。。。

YouTube動画:

 ビジュアル的な見せ場は 1分以降から。MSX のランダム関数を使って適当に図形を作画し、それを BGV として使っている。低解像度ながらも背景色がカラフルに変わり続けるので、視覚的なインパクトは大きいと思う。

 MSX(2+ 以降) で音声出力可能な『FM音源6音(音声5CH+リズム1CH)』と『PSG音源(3CH)』の全てを使って再生しているので、MSX とは思えないほど厚みのあるサウンドを実現できた。ボーカルパートも合成音声を使っている。バックコーラスも何となく「We Will We Will Rock You」って聞こえると思う。

 この合成音声は、自分自身はホーミー風の音声を作ったつもりだったんだけど、改めて聴くと『ジェフ・ベックがトーキング・モジュレターをくわえて演奏してる音』…みたいにも聴こえる。

 この音は MSX2+ での実行・再生音をそのまま MTR で録音した。MSX2+ は 8ビットCPU のパソコンでクロック周波数も低く、演奏テンポに実行が追い付かなくなって、たまに演奏がモタツクところがある。ターボR ならこういうことはないのだが、リズムの不安定な揺らぎも人間(MSXだけど)の持ち味だと思えば、さほど気にならない。


 やってみた…と言っても、これを作ったのは実は 1994年。インターネットは一部の人間しか利用してなかった時代だ。これをいつ・どのように公開するか、それが問題だった。最大の懸案は著作権の問題。

●オリジナル曲の情報:
曲名:We Will Rock You
演奏:Queen
作詞:Brian Harold May
作曲:Brian Harold May

参考音源1:New of the World / Queen …に収録(1曲目) (1977年 スタジオ盤)
参考音源2:Live Killers / Queen     …に収録(CD2-7) (1979年 ライブ盤)

●やってみた…の情報:
演奏:MSX,  Prog. & Arr. by foussin (FooSAN)
      (上記の参考音源を適度に混ぜたアレンジにして演奏)

 作詞・作曲はギターのブライアン・メイですな。著作権管理団体は外国にあるハズ。所属レコード会社の日本法人に連絡を取れば許諾申請は可能と思う。販売目的のデジタル配信という形で権利者にロイヤリティが入るようにすれば、案外すんなり許諾は取れるのかもしれない。

 しかし自分には、そういう商売スキルがない。でも公開はしたい。このままでは一度も日の目を見ずに終わってしまうと思うので、まずはお披露目をしておきたかった。今年になって MSX 実機を復活させたのは、実はこれをやりたかったためでもある。


 さて。

 YouTube では『やってみた系』の投稿動画作品については著作権侵害をある程度は不問とする協定が各著作権管理団体と結ばれている。これにはいくつかの条件があって、非営利目的であること、歌詞掲載・譜面掲載は原則 NG、替え歌や編曲 NG(著作人格権がらみ)、あとは肖像権を侵害しない等の常識的な条件をクリアしている必要がある。

 この中で『編曲 NG』という項目の判断が難しいところ。投稿者のスキルによってはオリジナルどおりの演奏は困難ということもあるし。だが、普通はオリジナルのデジタルデータに不当な編集を加えることを禁止するための条件と解釈すれば良いだろうと思っている。

 逆にオリジナルと同じ演奏を、オリジナルよりも上手に演奏されてしまったら、それはそれでオリジナル権利者のメンツを潰すことになって摩擦が生じる。やってみた系投稿のコツとしては『オリジナルよりも適度にヘタ』ということも重要な要素としてあるかもしれない(これについては自信満々だぜ!)。。。

 どうしても営利目的で投稿したい、歌詞掲載したい、という場合は権利者の許諾を取る必要がある。ロイヤリティが発生するなら権利者も許諾申請を無下にすることはないと思うし。


ソースコードは公開できない(と思う?):

 当作品の音源データは MSX-BASIC によって記述されている。ソースコードは foussin の著作物である…それは確かだが、コードの中には MML(ミュージック・マクロ・ランゲージ)で記述された譜面データも含まれている。

 MSX を持っているユーザーなら、このコードを使えば動画と同じ音楽が何度でも再生可能となる。これが作曲者の利益を損ねる可能性は、残念ながら否定できないと思う。そんなワケで、なんとも歯切れの悪い話だがブログでのソース掲載はしないことにした。代わりに動画の中でチラッと list 表示するシーンを入れたので、気になる人は参考にしてください。

 ネットの普及によって、今や誰もが著作物をリリースできる時代になった。意識する、しないに関わらず、誰もが著作権を持っている。自分の権利を主張するのと同じように他者の権利も尊重する…そこは大切にしていきたい。


元ネタ 本家オリジナル曲の配信先リンク(Google Play の音楽 より):

https://play.google.com/store/music/album/%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3_News_Of_The_World?id=Bz64r7utfddkz2kd5bonpk6yoza

https://play.google.com/store/music/album/%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3_Live_Killers?id=B4sqfqbilnkmhawo6jwputefgha



蛇足:

 動画編集では Corel VideoStudio Pro X8 という動画編集ソフトを使用。アルファチャネルを使った透明化処理のコツとか、多少は掴めてきた。個々の映像素材にはあまり意味はなく、音楽と映像のテンポを同期させて臨場感を出すことを重視している。

 そのうち、MSX で作ったこの音源をベーストラックにして、さらにギターとボーカルを被せてみたい…と思っている。


最後に(MSX 関連情報)…

1986年のアスキーとの提携解消の折に著作権をマイクロソフト、商標権(販売権)をアスキーが所有することになった。
(ウィキペディアより抜粋)

MSX は 株式会社MSXライセンシングコーポレーション(MSXアソシエーションではなくなった) の登録商標です。一応、これも書いておきます。

2016-05-10 Tue

語語(カタリガタリ) by Perl for Windows

【546】


 連休中に久し振りに Perl でプログラムを作った。自分のために作ったコードですが、フリーソフトとしてご自由にご利用ください。とりあえず『語語(カタリガタリ)』と名付けた。ファイル名は ktrgtr.pl とした。ネーミングは西尾維新風にしてみた。。。

#!/usr/bin/perl
# <title> 語語(カタリガタリ) by Perl for Windows </title>
#         ktrgtr.pl (KaTaRiGaTaRi) by foussin (v0.00) 2016.05.08 Sun
use strict;
use warnings;
use utf8;
use Encode qw/decode/;
use Encode::Guess qw/sjis euc-jp/;
use FindBin;
use Term::ReadKey;

use Win32::Console::ANSI; # Win専用モジュール?(WinでESCシーケンス使用)
print "\e[2J";            # CLS(クリアー・スクリーン)
$| = 1;                   # STDOUT のバッファリング止め

# ●Act.0:画面表示の文字コード (実行環境をここで特定)
#   ":encoding(cp932)" → Windows(コマンドプロンプト)
#   ":utf8"            → Linux 等
#   ※デコード済の内部表現文字列を binmode で 自動エンコード
my $console_code = ($^O eq "MSWin32") ? ":encoding(cp932)" : ":utf8";
binmode STDOUT, $console_code;  # 標準出力を画面表示に使う
binmode STDERR, $console_code;  # 標準エラー出力を画面表示に使う


# ●Act.1:表示モード選択
print <<"EOT";

0. だらだら表示モード
1. 単語区切りタップ入力モード(主に英文用)
2. 1文字タップ入力モード(主に童謡の歌詞用)
EOT
print "表示モードを選択(0-2)> ";
chomp(my $mode = <STDIN>);  # エラートラップ省いた…


# ●Act.2:初期設定(waitのデフォルト値)
my $wait_sec = 0;                   # 1文字タップ入力(童謡の歌詞用)
($mode==0) and $wait_sec = 0.06;    # だらだら表示モード
($mode==1) and $wait_sec = 0.01;    # 単語区切りタップ入力(英文用)


# ●Act.3:入力ファイル読込
my $ifile = $ARGV[0] ? $ARGV[0] : "";
unless ($ifile) {
    # 実行中のスクリプトが居る場所をカレントディレクトリにする
    chdir $FindBin::Bin;
    # glob で "./ktrgtr-*.txt" ファイルリストをメニュー表示
    # Windows では open用と表示用、2種類の配列が必要(binmode指定が逆に仇?)
    my @files = glob("ktrgtr-*.txt");                   # open用リスト
    my $num = @files or die "error: 入力テキストが見つからない!";
    my $files = decode("Guess", join("\n", @files));
    my @decode_names = split /\n/, $files;              # メニュー表示用
    for (my $i=0; $num>$i; ++$i) { print "\n$i. $decode_names[$i]"; }
    if ($num == 1) {
        $ifile = $files[0];
    } else {
        print "\n読込テキストを選択(0-", $num-1, ")> ";
        chomp(my $id = <STDIN>);
        $ifile = $files[$id];
        $ifile or die "error: 番号指定が変かも?";
    }
}
# 入力ファイルの文字コードは不明のままオープン
open(IN, "<", $ifile) or die "Error: $!";
# 入力文字列をまるごと配列に入れ、文字コードを推測し内部コード変換
my @src_text = <IN>;   close IN;
my $src_text = decode("Guess", join('', @src_text));


# ●Act.4:テキストのコメント行を除去
# ktrgtr.pl では、"# " (#と半角スペース)から始まり "\n" (改行)まで
# をコメント行として除去する。行の途中にコメントを入れると表示が乱
# れる。 コメントの記述は『1行コメント』のみ有効という仕様とする。
$src_text =~ s/# .*\n//g;
#print $src_text; # 動作確認用


# ●Act.5:テキストを表示モードに合わせて分割し @str に格納
my @str;
if ($mode==1) {
    # 1. 単語区切りタップ入力モード(主に英文用)
    # スペース(全角・半角)、句読点(、。)、\n で区切り文章を分割する
    # (区切り文字 の直後に『$■』を挿入し、最後に『$■』で split)
    $src_text =~ s/(\n+)/$1$■/g;          # 復改
    $src_text =~ s/([、。・=])/$1$■/g;   # 句読点・他
    $src_text =~ s/( +)/$1$■/g;          # 全角スペース
    $src_text =~ s/( +)/$1$■/g;           # 半角スペース
    $src_text =~ s/\n$■( +)/\n$1/g;      # 行先頭のスペースは対象外
    $src_text =~ s/\n$■( +)/\n$1/g;       # 行先頭のスペースは対象外
    $src_text =~ s/$■(\n+)$■/$1$■/g;  # 行末尾をひとまとめにする
    @str = split '$■', $src_text;         # テキスト → 配列
} elsif ($mode==2) {
    # 2. 1文字タップ入力モード(主に童謡の歌詞用)
    # 拗音(ゃゅょャュョ)、?(ぁぃぅぇぉァィゥェォ)、促音(っッ)、長音(ー)、
    # 句読点(、。,.)、スペース(全角・半角)、復改(\n)、記号等は直前の文字と
    # 連結して『1音節扱い』とする。
    # ($src_text を substr で 1文字ずつチェックしながら @str に push)
    $str[0] = "";   # 初期値はダミー
    my $len = length $src_text;
    for (my $j=0; $j<$len; ++$j) {
        my $ch = substr($src_text, $j, 1);
        if ($ch =~ /[ゃゅょぁぃぅぇぉっャュョァィゥェォッ…ー\-!!??==・、。,\.:;:;\(\)  \n]/) {
            push @str, pop(@str) . $ch;     # スタック操作
        } else {
            push @str, $ch;
        }
    }
    $str[0] or shift @str;
} else {
    # 0. だらだら表示モード
    $str[0] = $src_text;
}
#print join("●", @str); # 動作確認用
print <<"EOT";

準備完了:
何かキーを押すと CLS(画面クリア)してスタンバイ状態になります。
その後、もう一度適当なキーを押すと表示が始まります。

ご自分のタイミングでキーを押して実行開始してください。
EOT
ReadMode 4;         # Turn off controls keys(とりあえず 4 にしとけば OK)
my $x = ReadKey;    # 何かキーを押すまで wait を続行
print "\e[2J";      # CLS(クリアー・スクリーン)
#print "\e[5>h";     # カーソル非表示モード(Windows は使えないらしい)

# ●Act.6:@str の先頭要素を shift で取り出し、適度に wait をかけて表示
while (@str) {
    my $x = ReadKey;  # 何かキーを押すまで wait を続行
    my $str = shift @str;
    my $len = length($str);
    for (my $j=0; $j<$len; ++$j) {
        my $ch = substr($str, $j, 1);
        wait_on($wait_sec);
        print $ch;
    }
}
ReadMode 0;     # Reset tty mode before exiting
#print "\e[5>l"; # カーソル表示モードに戻す(Windows は使えないらしい)
sleep 2;
$| = 0;         # STDOUT のバッファリング復活
1;


# ●サブルーチン:wait_on (wait 実行ルーチン) by foussin
# 2005.11.05 Sat 10:21 (初版)
# 2012.05.15 Tue 23:42 (Perl5 風にリライト)
# 概要:1秒未満の wait をかける
#       最小単位:10ミリ秒=1センチ秒 (Win32 の場合) (Linux は 1ミリ秒)
#       最小単位は times の実装に依存 (Linux と Win32 では仕様が異なる)
#       0.01秒未満の秒数を指定すると 0.01 を指定したと見なされる(Win32)
# 備考:times の実装は 2012年当時の話(現在では仕様が変わっているかも…)
# 書式:$true_time = wait_on($sec);
# 引数:$sec: 0.01秒以上の wait時間(秒数)を指定する。
# 戻値:$true_time: 実際に wait した時間を秒数(実数値)で返す。
# 備考:実際の待ち時間は引数$secを超える可能性アリ (正確なwaitではない)
sub wait_on {
    my $start = (times)[0];
    my $sec   = $_[0];
    my $break = $start + $sec;
    my $now;
    while (1) {
        $now   = (times)[0];
        ($now >= $break) && last;   # 正確な wait ではない...
    }
    return $now - $start;
}
__END__

機能:テキストをコンソール(ターミナル)に『ゆっくり標準出力』する
書式:ktrgtr.pl [入力テキストファイル名]

引数:引数を省略すると ktrgtr.pl が居る場所をカレントディレクトリにして
   そこにある『ktrgtr-云々.txt』を入力ファイルとして読み込む選択画面
   となる。入力ファイルが 1個しかない時は選択プロンプトを表示せずに、
   そのファイルを直ちに読み込む。入力ファイルの文字コードは問わない。

カテゴリ:創作支援ツール(映像表現用)

 ソースコードは Windows 用になってるが、12行目の

use Win32::Console::ANSI; # Win専用モジュール?(WinでESCシーケンス使用)

…をコメントアウトすれば、Linux でも問題なく使えると思う(動作未確認)。ソースは utf8 で保存してください。

 以下のページ(サンプル置き場)からも DL できます。ソースが表示されたら『名前を付けてページを保存』で ktrgtr.pl の名前で保存してください(文字コード UTF-8、復改 LF のテキストファイルで保存されます)。

http://blue.zero.jp/foussin/cgi/src/fs-utl/_tiny_tools/ktrgtr.pl_utf8.txt


 約180行(3分の1ぐらいはコメントなので実質120行ぐらい)。使い方は __END__ 以降のコメントに書いた。基本は『動画用の字幕』をコンソール上に表示して、それを後で動画編集ソフトで合成して使う…という使い方になる。


実行手順:

 実行すると次のような画面が表示される…

0. だらだら表示モード
1. 単語区切りタップ入力モード(主に英文用)
2. 1文字タップ入力モード(主に童謡の歌詞用)
表示モードを選択(0-2)> 0

0. ktrgtr-アルプス一万尺.txt
1. ktrgtr-奥の細道(松尾芭蕉)-草の戸(冒頭部分).txt
2. ktrgtr-星の王子さま名言.txt
3. ktrgtr-rock-you-singing.txt
読込テキストを選択(0-3)> 1

準備完了:
何かキーを押すと CLS(画面クリア)してスタンバイ状態になります。
その後、もう一度適当なキーを押すと表示が始まります。

ご自分のタイミングでキーを押して実行開始してください。

 最初に『表示モード』を選択。次に『読込テキスト』を選択する。読込テキストは ktrgtr.pl が入っているフォルダの『ktrgtr-云々.txt』が表示される。テキストの文字コードは問わない。


事前準備:

 読込テキストが必要。今回は実行例を説明するために、次のようなテキストを作っておいた。今回は作者不詳とか大昔の作家の作品を使っている。これなら著作権的に掲載可能なので。

# ktrgtr-アルプス一万尺.txt
# 1文字タップ入力モード用のテキストの例

# 作曲者:不明(アメリカ民謡)
# 作詞者:不明
# 題 名:アルプス一万尺 (手遊び唄)
  アルプス一万尺

  小槍の上で

  アルペン踊りを

  さあ踊りましょ!


# ktrgtr.pl では、"# " (#と半角スペース)から始まり "\n" (改行)までを
# コメント行として除去します。行の途中にコメントを入れると表示が乱れ
# ます。コメントの記述は『1行コメント』のみ有効という仕様とします。

# ktrgtr-奥の細道(松尾芭蕉)-草の戸(冒頭部分).txt
# だらだら表示モード用のテキストの例


 奥の細道 草の戸(冒頭部分):松尾芭蕉


  月日は百代(はくたい)の過客にして、行きかふ人もまた旅人なり。

  舟の上に生涯を浮かべ、馬の口とらへて老いを迎ふる者は、

  日々旅にして、旅を住みかとす。古人も多く旅に死せるあり。

  予も、いづれ… (後略)

# ktrgtr-星の王子さま名言.txt
# 単語区切りタップ入力モード用のテキストの例


  It is only with the heart that one can see rightly;
  what is essential is invisible to the eye.


  心で見なくちゃ、ものごとは よく見えないってことさ。
  かんじんなことは、目に見えないんだよ。


 …星の王子さま(アントワーヌ・ド・サン=テグジュペリ・著)より
# アントワーヌ・ド・サン=テグジュペリ(1900年〜1944年)
# Antoine de Saint-Exup?ry ←(UTF-8:euc-jp, shift_jis では表示不可能)


実行例:

まずは『コマンドプロンプト』での実行風景(動画):


語語(カタリガタリ) ktrgtr.pl には 3つの表示モードがある。


『0. だらだら表示モード』の例:

 奥の細道(冒頭)。コマンドプロンプトを半透明にして、動画で使う静止画像が透けて見えるようにしているのがポイント。


『1. 単語区切りタップ入力モード(主に英文用)』の例:

 星の王子さまの有名な一節。個人的にはけっこう気に入っている。字幕に気を取られていると後ろに見えるモンシロチョウ(メインビジュアル)を見落としてしまう。雑に作っている割には、意外と文章とマッチした映像表現になっている気がして。。。


『2. 1文字タップ入力モード(主に童謡の歌詞用)』の例:

 アルプス一万尺の歌詞。音楽に合わせてキーをタップすることで、手軽に字幕と音楽を同期させている。


 実行中にカーソルがチラチラ見えるのがウザいが、Windows ではこれを非表示にする方法が分からなかった。Linux の場合、125行目を

print "\e[5>h";     # カーソル非表示モード(Windows は使えないらしい)

…にすれば、たぶんカーソルを消せると思う(動作未確認)。さらに 139行目を…

print "\e[5>l"; # カーソル表示モードに戻す(Windows は使えないらしい)

…とする。ちなみに、"\e[5>h" とか "\e[5>l" というのは『エスケープ・シーケンス』である。

 自分にとって、このコードはかなり使えると思っているが、一般ユーザーの目にはしょぼく見えるだろうな…。というわけで、詳しく説明するモチベーションが湧いてこない。中途半端な説明で申し訳ないが、このネタはこれでおしまい。

 また、しばらくの間、休眠状態に入るかもしれない。。。

2016-04-17 Sun

イノシシの鼻息 by MSX

【545】


 前回は休眠すると書いたが、やはり月イチぐらいは何か投稿したい。が、今は特に書くこともないので、過去の蔵出しを引っ張り出すことに。もうしばらく MSX ネタが続くかも。。。

 今回は 1994年 MSX・FAN の『AVフォーラム』に投稿し、掲載されたジョークソフト作品を貼ってみる。MSX を使っていた当時の自分は、テキスト処理やグラフィック処理よりも、むしろ SOUND文、PLAY文を使ったコードを書く方が得意だった。それにはやむを得ない事情もあったのだが、それについては別の機会に書こうと思う。

YouTube動画:

基本的に『ターボR』用。MSX2+ でも動くが、動きがもたついて面白さが出ない。

10 '(C)1994 FooSAN  Title:「イノシシ ノ ハナイキ」 (11/25-28mon)
20 'VRAM64Kイジョウ,MSX2イコウ ノ キシュ デ ウゴキマス.
30 'ANKモード デ ジッコウ シテクダサイ(_ANK ハ 2+イコウ ノ メイレイ ナノデ ツカイマセン デシタ).
70 '     12345678
80 'save"hanaiki .bas",a
90 :
100 CLEAR1000:SCREEN0:WIDTH40:DEFINT A-Z:PL$="olsmv":PI#=3.1415926535898#
110 DIM TN(209),TS(209),V(209),R6(209),R7(209)
120 PRINT"^ ^":PRINT"` '; イノシシ ノ ハナイキ(ノ ツモリ!)":PRINT" O   (C)1994 FooSAN"
130 PRINT:PRINT"ゲンザイ ノ モード ハ ドッチ ?":PRINT
140 PRINT"1.ヒョウジュン モード":PRINT"2.コウソク モード(ターボR)":PRINT:PRINT"Select(1/2)>";
150 I$=INPUT$(1):I=VAL(I$):WT=(-1)*(I=1)*160+(-1)*(I=2)*900
155 SW=(-1)*(I=1)*100+(-1)*(I=2)*6
160 IF WT=0 THEN 150 ELSE PRINT I:ON STRIG GOSUB 260:STRIG(0) ON:R=RND(-TIME)
170 PRINT:PRINT"Wait a moment,please・・・";:X=POS(0):Y=CSRLIN
180 FOR J=204 TO 0 STEP-1:LOCATE X,Y:PRINT J
190  TN(J)=RND(1)*256:TS(J)=RND(1)*16:V(J)=RND(1)*9+8:R6(J)=RND(1)*32
195  R7(J)=RND(1)*3+5
200 NEXTJ
210 SCREEN5:R=6:G=3:B=1:COLOR=(3,R,G,B):OPEN"grp:"AS#1
220 DP=1:AP=1:R=80:GOSUB330:DP=0:AP=0:R=100:GOSUB330
230 '---Main loop---
240 GOSUB280:DP=ABS(DP-1):SET PAGE DP:RL=RND(1)*WT+1:FORT=0 TO RL:NEXTT
250 SOUND8,0:SOUND9,0:SOUND10,0:FOR T=0 TO WT/SW:NEXTT:GOTO240
260 '---STRIG(0) END sub---
270 CT=205:GOSUB280:COLOR:CLOSE:SOUND7,&B111000:PLAY PL$,PL$,PL$:PRINT:END
280 '---SOUND Generator sub---
290 SOUND7,R7(CT):SOUND6,R6(CT):SOUND0,TN(CT):SOUND1,TS(CT):SOUND2,TN(CT+1)
295 SOUND3,TS(CT+1)
300 SOUND4,TN(CT+2):SOUND5,TS(CT+2):SOUND8,V(CT):SOUND9,V(CT+1)
305 SOUND10,V(CT+2)
310 SOUND11,TN(CT+3):SOUND12,TN(CT+4):SOUND13,TS(CT+3)
320 CT=CT+3:CT=(CT<200)*(-1)*CT:RETURN
330 '---GRAPHICS sub---
340 SET PAGE DP,AP:COLOR15,12:CLS:CIRCLE(128,106),110,3:PAINT(128,106),3
350 LINE(58,116)-(18,156)  :LINE-(68,136) :LINE-(58,116) :PAINT(48,136)
360 LINE(198,116)-(238,156):LINE-(188,136):LINE-(198,116):PAINT(208,136)
370 CIRCLE(128,106),R,9,,,.6:PAINT(128,106),9
380 CIRCLE(88,106),R/4,1:CIRCLE(168,106),R/4,1:PAINT(88,106),1:PAINT(168,106),1
390 CIRCLE(78,40),R/20,1:PAINT(78,40),1:CIRCLE(128,106),80,1,5/4*PI#,7/4*PI#
400 CIRCLE(178,40),R/20,1:PAINT(178,40),1
410 PRESET(30,0):PRINT#1,"ヤメル トキハ SPACE KEY ヲ オシテ ネ。":RETURN

2016-03-09 Wed

回転夜空 by MSX ...

【544】【制作メモ】

 久し振りの長文です。euc-jp(復改LF)のテキストで 16KBもある。『記事を書いた日数 1000日』を目指して、記事を分割して細かく投稿することも考えたが、今回は勢いが大事。今回のコードは 3月3日頃から書き始めて一気に作り上げた。このテンションを長期間維持するのは今の自分には無理…もうトシなので。


 最近、アニメの ED とかで夜空の星が回転する映像をよく見る。で、制作スタッフがやりたかったのは、たぶんこういうことなんだろうな…と思って作ってみた。MSX で。

00-動画の例(超早回し再生)


 BGM(モノラル・FM音源)も MSXで適当に作っている…大昔に作ったホンキートンク調ジャズ(?)自動作曲プログラム。そのコードは、今は秘密にしておく。意外かもしれないけど、昔の GLOBE のようなド派手サウンドでも "回転夜空" のビジュアルとは案外マッチしたりする。


 ただ、MSX の解像度が低すぎて円弧の線にジャギーが出たり、線が太くなってしまう。それをごまかすためにピンボケにしたり露出アンダーにしたりガウスぼかしをかけたり、いろいろ…。MSX の解像度では 16:9 の HD サイズには対応不可能なので、VGA サイズで撮影(または画面キャプチャ)したものを 16:9 の画面にハメ込んで使う…そういう使い方になりそう。

ファイル名:r-stars0.bas, rstars.bas の 2つ

置場(url) :
http://blue.zero.jp/foussin/cgi/src/msx/r-stars/r-stars.bas.txt
http://blue.zero.jp/foussin/cgi/src/msx/r-stars/r-stars0.bas.txt
(ブラウザでは表示できないかもしれない。その場合は保存となる)

r-stars0.bas (version 0) ... 初版
r-stars.bas  (version 1) ... 改良版

2つのファイルは微妙に仕様が違うが、映像素材として
利用するなら改良版の方が便利かな、と思う。

 ダウンロードファイルの名前を r-stars.bas.txt → r-stars.bas にリネームすると MSX で実行できるようになります。当ファイルは NYSL(煮るなり焼くなり好きにしろライセンス) または PDS として公開します。ご自由にどうぞ(主に映像作品用の背景素材として使われることを想定)。

 別の言語に移植するのも自由です。MSX BASIC でも作れたんだから、Visual BASIC でも作れるんじゃないかな。本当は Script-Fu(GIMPプラグイン) で作りたかったんだけど(その場合は数メガバイト単位の GIFアニメに仕上げる体裁になったと思う)。残念ながらウチの Script-Fu が動かなくなってしまったので…そこで自分の原点ともいえる MSX 復活劇となった。。。

 ターボR での実行を推奨。自分の MSX2+ (A1 WX) はメインメモリが 320Kバイトあるので特に問題なく動作したが(実行が遅い以外は)、64K の環境だと問題が起こるかも(動作未確認)。MSX 実機を持ってない人はターボRエミュレータを使うと良いでしょう。


ここから制作メモ:

screen 5 (256x212 dot : 512色中16色) を使用:

 screen 8 の 256色カラーだと青が 2ビット(0-3)しか使えないので、夜の濃い青が表現できない。screen 5 なら RGB が各 3ビット(0-7)使えて、濃い青のグラデーションが表現できるかも。。。

カラーパレット(備忘):color=(パレットNo, R, G, B)
(パレットナンバー『0』は透明色…未使用)


●背景:夜空

 回転夜空を作る前に、サンプルとして『hakmei.bas(薄明・夜明け前)』を作ってみるのが良さそう。やはり、いきなり作るのはムリ。

10 ' 美乳 (sjis モジ バケ タイサク)
20 ' ハクメイ (ヨアケ マエ)
30 :
80 'save"hakmei.bas",a
90 :
100 SCREEN 5 : CLS
110 ' ハイケイ (パレット No.1)
120 COLOR=(1,0,0,0) : COLOR 15,1,1
130 :
140 FOR DB=0 TO 7   'DB(dark blue)
150   COLOR=(1,0,0,DB):COLOR ,1,1
160   FOR T=0 TO 1000:NEXT T
170   BEEP
180 NEXT DB
190 COLOR=NEW : END
^Z

 パレットの変更は色の塗り直しをしないので一瞬で色が変更できる。16色しか使えなくても 8階調のブルー・グラデーションは効果が期待できる…と思ったけど、8階調でグラデーションは無理だった。


 星が15度回転するごとに背景のパレットカラーを明るくする(ver0 の場合:blue を 0,1,2)。0度から30度の範囲で計 3回 背景色を変更。30度以降は色を変えず、45度まで回転させる。地球は 1時間で15度自転するので、45度は 3時間分のシミュレーションとなる。深夜 2時頃から夜明け前の 5時頃を想定。

 ver1 では頻繁に色を変えることはやめているが、その代わりに実行前に背景色を選べるようにした。


●pset でゆっくり円を描く

 とりあえず 1個の円を描くサンプルコード。

10 ' 美乳 (sjis モジ バケ タイサク)
20 ' pset, sin, cos デ ユックリ エン ヲ エガク
30 :
80 'save"sin-cos.bas",a
90 :
100 CX=127 : CY=105 'center
110 RD=60           'ハンケイ r
120 PI=3.14159265358979#
130 L =2*PI*RD  'エンシュウ len
140 RT=(2*PI)/L 'サイショウ カイテン カク
150             '(テンヲ ツナゲテ ジッセンニ スル)
160 'itv==1 ナラバ ジッセン(2 イジョウ ハ テンセン)
170 INPUT"テン ノ カンカク(1.0 - 10.0) ";ITV
180 RT=RT * ITV
190 SCREEN 8 : COLOR 15,1,1 : CLS
200 :
210 ' &B gggrrrbb (256c)
220 ' g(0-7)*32 + r(0-7)*4 + b(0-3)
230 G=RND(-TIME)
240 G=INT(RND(1)*6)+2 'アカルメ ノ イロ(2-7)
250 R=INT(RND(1)*6)+2
260 B=INT(RND(1)*2)+2
270 C=G*32 + R*4 + B
280 :
290 ' t(カクド theta)
300 FOR T=0 TO 2*PI STEP RT
310   X=RD*COS(T)+CX
320   Y=RD*SIN(T)+CY
330   PSET(X,Y),C
340 NEXT T
350 A$=INPUT$(1) : END

 点の間隔を変えられるようにしたのは意外と良いと感じた。ビジュアルとして面白くなりそう…これは採用。間引き運転なので実行速度も速くなるし。ただ、小さい半径の星は繋がって実線になってしまうだろうけど。

 星々をすべて同時に回転させるには『始点座標』を求めるよりも『半径』と『開始角度』のリストを配列に格納する方が合理的だと分かる。あと、MSX の ATN 関数がレガシー仕様なので、ATN を使うのを避けた、という事情もある…。

 最小回転角は一番大きな半径から算出し、すべての星にそれを適用する。そうしないと各星の移動距離が同期しないので。半径が小さすぎると端数誤差が原因となって軌道がジグザグになる(線が太くなる)ので、半径の最小値を制限した方が良さそう。とはいっても半径 20ぐらいの小ささは必要(特に北向きの場合は)。

 最小回転角をループごとに加算するカウンタ変数を用意し、各星の開始角度に加算(北向きの場合は減算)し、その都度座標計算する。カウンタ変数が15度(のラジアン)を超えたかどうか判定し、超えたら背景色を明るくする。ついでに BEEP音も鳴らす(この辺の仕様は v1 と v2 で微妙に違いがある)。

 求めた座標は 1ループ分だけ配列に記憶しておく。カウンタが 45度(4分のpiラジアン)を超えたら回転を止め、最後の座標配列を使って星を点滅させる。点滅には適度にカラーパレットを更新するルーチンを組めばいい。

 円弧の方も、最後は背景色のカラーパレットを半透明(残像っぽく)処理したいところ。出来そうならやってみるが、実行環境がスペックの貧弱な MSX であることを考慮すると、これ以上のアップデートは難しいかもしれない…(結局やった)。


 上記のサンプルでは screen 8 を使ってるが、今回はパレットを使いたいので screen 5 を採用(画面解像度はどっちも同じ→ 256 x 212 ドット)。モニタのピクセル数とは随分違うので。。。

 星の数は 20個以内の範囲が妥当と考える。それ以上はハード・スペック的にキツイ(MSX2+ の場合)。円弧を描くので、さほど疎らな印象は受けないと思う。ターボRなら、まだ余裕だと思うけど…。上限のチェックはしないので、ターボRを使う人は遠慮なく21個以上の星を指定していいことにする。

 最後にベタ画像を r-stars.pic として保存。気に入った画像だったら後でリネームして上書きされないようにする…と思ったけど、ランダム関数の実行結果なんて一期一会でいい。面倒くさくなったのでこれはヤメ。

 -TIME (乱数の種)を記憶しておけば、画像を BSAVE しなくても何度でも同じ描画が再現できるが、それは『ハードが変わらないならば』という条件が付く…いろんな機種(エミュレータも含む)で実行する人も居るし、やっぱりヤメ。


●カラーパレット内訳 (Screen 5, 512色中16色パレット使用可):

0 ...... 透明色(未使用)
1 ...... 背景色(黒〜濃い青:Blue BIT => 0〜2)
2〜 8 .. 7パレット:円弧の色として使用
9〜15 .. 7パレット:星の点滅用として使用(フィニッシュ)

円弧は残像なので、それが点滅すると変になってしまうので、
円弧用と点滅用のパレットを分ける。

選択メニュー表示(備忘):

  select:厳選する(良いものだけを選ぶ)
  choice:普通に選ぶ


●コーディング開始(ver1 のソース):

10 ' 美乳 (sjis モジ バケ タイサク)
20 ' <title>回転夜空(v1) by MSX</title>
30 ' +-------version 1-------+
40 ' |  カイテン ヨゾラ .. by MSX  |
50 ' |  revolving stars (?)  |
60 ' |  by foussin  (2016.3) |
70 ' | (エミュレータノ ジッコウモ コウリョ) |
80 'save"r-stars.bas",a
90 :
100 ' init.
110 SCREEN 0 : COLOR 15,1,7 : CLS
120 PI =3.1415926535898#
130 A  =RND(-TIME)  ' a(ツカイ マワシ ヘンスウ)
140 ADD=0       ' サイショウ カイテンカク カサン ヨウ
150 CT =0       ' 15ド ゴトニ カウント
160 :
170 PRINT "ハイケイ ショク ハ ?"
180 PRINT "0. クロ(RGB=000)"
190 PRINT "1. コン(RGB=001)"
200 PRINT "2. アオ(RGB=002)"
210 PRINT "3. 1カイ ダケ カエル(001 -> 002)"
220 INPUT "choice(0-3)"; BC  ' BgColor
230 ' ハイケイ ショク ショキチ (P: パレット No.1)
240 IF BC=3 THEN B=1 ELSE B=BC
250 COLOR=(1,0,0,B)         '(P,R,G,B)
260 :
270 ' チュウシン ザヒョウ  (cx, cy)
280 ' ハンケイ min,max (r0, rz)
290 PRINT:PRINT "ミル ホウガク ハ ?"
300 PRINT " 0. South(ミナミ)"
310 PRINT " 1. North(キタ)"
320 PRINT " 2. East (ヒガシ)"
330 PRINT " 3. West (ニシ)"
340 INPUT "choice(0-3)"; A
350 IF A=0 THEN CX= 128:CY=260:R0= 80:RZ=300
360 IF A=1 THEN CX= 128:CY= 60:R0= 15:RZ=200
370 IF A=2 THEN CX= 350:CY=220:R0=120:RZ=400
380 IF A=3 THEN CX=-100:CY=220:R0=120:RZ=400
390 ' カイシ カクド min,max (t0, tz)
400 IF A=0 THEN T0=1.1*PI:TZ=1.7*PI 'S
410 IF A=1 THEN T0=0     :TZ=2*PI   'N
420 IF A=2 THEN T0= .9*PI:TZ=1.4*PI 'E
430 IF A=3 THEN T0=1.6*PI:TZ=1.8*PI 'W
440 :
450 PRINT:INPUT "ホシ ノ カズ(1-20)"; N
460 :
470 ' itv=1 ナラ ジッセン(2 イジョウ ハ テンセン)
480 INPUT "テン ノ カンカク(1.0-10.0)"; ITV
490 :
500 ' ** ハイレツ 5コ センゲン & ダイニュウ **
510 ' ハンケイ(rd)  &  カイシ カクド(st)  &
520 ' 1 loop ブン ザヒョウ (qx, qy)  &
530 DIM RD(N-1) : DIM ST(N-1)
540 DIM QX(N-1) : DIM QY(N-1)
550 DIM CC(N-1) ' カラーコード(パレットNo)
560 PRINT : PRINT "ケイサン チュウ"
570 FOR I=0 TO N-1
580   RD(I)=INT(RND(1)*(RZ-R0))+R0
590   ST(I)=RND(1)*(TZ-T0)+T0
600   ' サイダイ ハンケイ (rr)
610   IF I=0 THEN RR=RD(0)
620   IF I>0 THEN IF RD(I)>RD(I-1) THEN RR=RD(I)
630   PRINT ".";
640 NEXT I : PRINT
650 :
660 ' サイショウ カイテン カク (rt)
670 L =2*PI*RR  ' エンシュウ len
680 RT=(2*PI)/L ' サイショウ カイテン カク
690 RT=RT * ITV ' テンヲ ツナゲテ ジッセンニ スル
700             ' (マタ ハ テンセン ニ スル)
710 ' キタ(North) ノ バアイ => ギャク カイテン
720 IF A=1 THEN RT=RT * -1
730 :
740 ' ホシ ベツ カラーコード セッテイ
750 ' 2-8:エンコ ヨウ, 9-15:テンメツ ヨウ
760 ' エンコ ノ カラーコード +7 => テンメツ ヨウ ト スル
770 FOR I=0 TO N-1
780   CC(I)=INT(RND(1)*7)+2 '(2-8)
790   PRINT "*";
800 NEXT I : PRINT
810 :
820 ' *** ココカラハ ビョウガ シナガラ ケイサン ***
830 SCREEN 5 : CLS : COLOR=(1,0,0,B)
840 :
850 ' カラーパレット(2-15): イロ ツクル
860 DIM R1(8) : DIM G1(8)
870 FOR I=2 TO 8
880   GOSUB 1340 'カラーパレット:イロ ツクル
890   R1(I)=R-1     ' アト デ エンコ ヲ
900   G1(I)=G-1     ' クラク スル.
910 NEXT I
920 FOR I=9 TO 15
930   GOSUB 1340 'カラーパレット:イロ ツクル
940 NEXT I
950 ' キタ(N) ノ バアイ => ホッキョク セイ (9-15)
960 PSET(CX, CY), INT(RND(1)*7)+9
970 :
980 ' ******* メイン loop *******
990 FOR I=0 TO N-1
1000   QX(I)=RD(I)*COS(ST(I)+ADD)+CX
1010   QY(I)=RD(I)*SIN(ST(I)+ADD)+CY
1020   PSET(QX(I), QY(I)), CC(I)
1030 NEXT I
1040 ' 15ド(pi/12) コエル ゴトニ BEEP ヲ ナラス
1050 IF ABS(ADD)>PI/12 AND CT=0 THEN GOSUB 1400 '15
1060 IF ABS(ADD)>PI/6  AND CT=1 THEN GOSUB 1400 '30
1070 IF ABS(ADD)>PI/4 THEN 1130 '45 ド
1080 ADD=ADD + RT
1090 GOTO 990 ' メイン loop
1100 :
1110 ' ******* エンコ stop *******
1120 ' エンコ ヲ クラク (ハントウメイ ポク) スル
1130 BEEP:FOR I=2 TO 8
1140   COLOR=(I, R1(I), G1(I), 4)
1150 NEXT I
1160 ' ホシ ノ カラーパレット ヘンコウ
1170 FOR I=0 TO N-1
1180   PSET(QX(I), QY(I)), CC(I)+7
1190 NEXT I
1200 ' テンメツ start(loop)
1210 R=INT(RND(1)*8)   '(0-7)
1220 G=INT(RND(1)*8)
1230 B=INT(RND(1)*8)
1240 P=INT(RND(1)*7+9) '(9-15)
1250 COLOR=(P,R,G,B)
1260 IF INKEY$ <> "" THEN 1290
1270 GOTO 1210 'テンメツ loop
1280 :
1290 COLOR=NEW : END
1300 :
1310 ' *** カラーパレット(2-15): イロ ツクル ***
1320 ' アカルスギル ト セン ガ フトク ミエテ シマウ ガ
1330 ' エミュレータノ キャプチャナラ ヤヤ アカルメ デ イイ
1340 R=INT(RND(1)*2)+3  '(3,4)
1350 G=INT(RND(1)*2)+3  '(3,4)
1360 B=INT(RND(1)*3)+3  '(3,4,5)
1370 COLOR=(I,R,G,B) : RETURN
1380 :
1390 ' **** 15ド ゴトニ BEEP ヲ ナラス ****
1400 ' 30ド ノ トキニ 1ドダケ ハイケイショクヲ カエル
1410 IF CT=1 AND BC=3 THEN COLOR=(1,0,0,2)
1420 CT=CT+1 : BEEP : RETURN

コーディング終了。(2016.03.06 Sun)

10 ' 美乳 (sjis モジ バケ タイサク)

 最初のこの行は文字化け対策用。Windows で編集した sjisソースを MSX で読んでも文字化けは起こらない。MSX は MS 漢字コード(sjis)以外の文字コードを知らないので。

 だが、文字コードを自動判別するエディタで『半角カナ混在の MSX BASIC ソース』を読み込むと、稀に EUC-JP と誤判定して文字化けする。sjis の半角カナは euc の使用領域と重複しているため、これを正確に判定するのは単語解析でもしない限り不可能だ。

 sjis の文字化け対策としてレガシーな方法がこれ。sjis テキスト行の先頭に『美乳』と記述する。詳細は省く。


 北半球専用。動画に仕上げた後で『全フレームを左右反転』して順再生すれば南半球での回転夜空になる。逆再生だと円弧が次第に短くなるので駄目。この実行画面は不可逆ってこと。


 基本は三角関数を使って pset で円弧を描くというもの(メインルーチンの for ループ参照)。当ダイアリーでも Perl や Script-Fu でさんざん使ってきた常套テクニックにすぎない。

 MSX BASIC の場合、ATN 関数(アークタンジェント)の戻り値の範囲が -pi/2 〜 +pi/2 なので、x座標が負数になる時(角度が鈍角になる時)の場合分けを考える必要がある。それがちょっと面倒。ということで、ATN を使わない方向でコーディングした。


プログラムの起動:

f:id:foussin:20160309040436j:image

01-ユーザー入力画面.jpg

 これはアスキー社の MSXPLAYer(MSXエミュレータ)。通常のエミュレータは仮想フロッピーを作って、それでファイルアクセスをするが、MSXPLAYer は『実フロッピー』でファイルを読み込めるので便利だ。画面のフロッピーアイコンの一番右の『FDD』というのが実フロッピーでアクセスするボタンになっている(実フロッピーはドライブA: となる)。ただし、このエミュレータが FDD を使用している間は別タスクで FDD を使うことは一切できなくなるので、そこは注意が必要(アクセスが拒否される)。

 さて。r-stars.bas (回転夜空) を RUN すると、最初にユーザー入力を求めるメニューが表示される。が、半角カナなので分かりにくいと思うので説明しておく。

    表示                        意味
--------------------------------------------------------------------
ハイケイ ショク ハ ?                    背景色は ?
0. クロ(RGB=000)                  0. 黒
1. コン(RGB=001)                  1. 濃紺
2. アオ(RGB=002)                  2. 濃い青(というか紺色かな)
3. 1カイ ダケ カエル(001 -> 002)      3. 最初は『1. コン』の色で、星が 30度
                                   まで回転すると『2. アオ』に変わる。

choice(0-3) ?                   0,1,2,3 の番号を 1つ選択し、最後に
                                エンターキーを押す。

ミル ホウガク ハ ?                    見る方角は ?
ホシ ノ カズ(1-20)?                 星の数 ?

これは説明しなくても分かると思うので省略。
もちろん、星の数が多くなると実行速度にも影響が出る。

テン ノ カンカク(1.0-10.0)?            点の間隔?

                                このプログラムは、無数の点を繋げて
                                円弧を描く。1 を指定すると『実線』に、
                                2 以上を指定すると『点線』になる。

 点の間隔を 1(=実線) にすると、円弧上に隙間なく点を打つので実行に時間がかかる。それに、逆にジャギーが目立つようになる。さらに実線は、夜空の尺度と比べると妙に太く見える。そんな訳で 1.2〜1.5 ぐらいを指定するのが無難と感じている(MSX 実機で実行する場合)。エミュレータで実行する場合は間隔1 でも大丈夫っぽい。

 この入力画面ではエラートラップを作ってないので、想定外の文字列を入力するとエラーで止まる可能性がある(ディビジョン・バイ・ゼロとか)。リターンキーだけを押してもデフォルト設定が適用されたりはしないので念のため。。。


 『見る方角』でひとつ補足。『2.東』と『3.西』の描画では、最大半径が大きく設定されている。これは円弧の点を打つ回数が多い=実行に時間がかかることを意味する。MSX2+ の実機だと、実行終了まで 30分以上かかるので、そこは覚悟してください(0.南, 1.北でも20分ぐらいはかかる)。

 ターボR では 2〜3分で実行終了するので MSX2+ より10倍速い。が、実行画面をカメラでインターバル撮影してタイムラプス動画や GIFアニメに仕上げるなら、実行速度が遅いことは逆に利点でもある。映像信号がアナログケーブル接続のモニタで表示すると『色のにじみ』などが出て、それが逆にリアルさを演出することもある。

 必ずしもデジタルがいい、速ければいい、というワケではない。


MSX2+ 実機での実行風景(適当にGIFアニメ化):

f:id:foussin:20160309040437g:image

02-南向きgif

f:id:foussin:20160309040438g:image

03-北向きgif

北の空では北極星を中心に反時計回りで星が回転する(北半球の場合)。

f:id:foussin:20160309040439g:image

04-東向きgif

f:id:foussin:20160309040440g:image

05-西向きgif

まあ、真東・真西ではなくて、だいたい東、だいたい西…みたいな感じ。


 もうひとつ補足。指定した『星の数』が必ず画面上に表示されるとは限らない。画面座標の外側で 1度も表示されない星もけっこうあるので、実際は指定した数よりも少なくなります。これは仕様ということで。。。


以上(またしばらくブログを休眠するかも…)。