ラベル 独自音源 の投稿を表示しています。 すべての投稿を表示
ラベル 独自音源 の投稿を表示しています。 すべての投稿を表示

2014年1月10日金曜日

VGS chiptune music(考察)

東方BGM on VGS(東方VGS)のバージョン1.00が無事リリースされ、ピスコラやMMLを打ち込まない日々が、数日間続いてますが、まるで、糸が切れた凧のような気分です。だからといってすぐに東方VGSを再始動させたい訳ではないですが。^^;

暫く、凧らせてくださいw

実のところ、あまり惚けている訳にもいきません。次はニコニコ動画の自作ゲームフェス3向けの新作に取り掛かる予定なので。その新作ゲーム開発のことはさておき、とりあえず、東方VGSのことを色々と振り返ってみよう・・・と、思ったのですが、東方VGSのことは、既にこのブログで何度か記事を書いているので、VGSの波形メモリ音源について振り返ってみたいと思います。

波形メモリ音源を作った経緯

このブログの2012年3月3日の記事3月17日の記事に、完成するまでの奮闘記みたいな記事が書かれています。(※若干、関係無い記事も混じっていますw)

実は、VGSの波形メモリ音源+音源ドライバ(MMLコンパイラを含む)は、2週間という短期間で完成させました。今、軽く読み直してみましたが、オリジナルの波形メモリ音源エミュレータ(ソフトウェアシンセサイザ)を、「あーでもない」、「こーでもない」と試行錯誤しながら完成させていく様が、中々微笑ましいですw

私は、VGSを作る以前から、音源エミュレータを実装することに興味があったのですが、技術的に色々と難しそうだと思って、躊躇していました。ついでに、作るのが大変な割りに、ありがた味(?)みたいなものが少ないんじゃないかと(OGGやMP3とかで別に良いんじゃない?とか)思っていた節もあります。

しかし、スマートフォンの場合、パソコンと違って容量が小さいし、不安定なワイヤレス通信だから容量が大きなアプリは嫌われます。そこで、スマートフォンアプリの開発に乗り出す以上、独自のソフトウェアシンセサイザを作ることには、モノ凄く大きな効果があるんじゃないだろうか...と、錯覚し、勢いに任せて作ってみた感じです。

■性能重視の音源仕様

開発奮闘記(?)の記事を読んでみると、私は「性能」というキーワードに敏感な事に、気付かれるかもしれません。これは、「音楽」というのはゲームにとっての「おまけ」であり、音楽の為にリソースを割くことを嫌っていたためです。(単に、プログラマの職業病という側面も無くは無いですが)

ですが、「ゲームに音楽が無くても良い」とは考えていません。
むしろ、「ゲームに音楽は必須だ」と考えています。
しかし、「性能を割くのはナンセンスだ」と考えた訳です。
そこで、「必要最小限のCPUリソースで、必要最大限の音楽演奏機能を作ること」を、設計目標に据えて、処理が重くなりそう&無駄な機能を最大限に削ぎ落とした形にデザインしました。

VGSの音源スペックが若干(かなり?)ショボイのは、その所為ですw

しかし、それでも東方VGSを聴いて頂ければ分かるように、十分ゲーム用のBGMとして成立できる音楽が鳴らせているんじゃないかと思います。(東方VGSの場合、思い出補正によるところが若干強いかもしれませんが)

■割とウケた(World Wideで)

波形メモリ音源を搭載したVGSで開発した処女作、「NOKOGI Rider」をAndroid Market(Google Play)でリリースしてみたところ、国内外問わず、その音楽を鳴らす仕組みに感心が集まりました。特に、海外からの反応が多かったと思います。

「こんな小さな容量でどうやってるんだ!」とか、
「日本製なのに快適に動く!」とか。
※日本製のゲームは、性能要件がキツイものが多いと見られているようです。

海外展開に苦戦している日本のデベロッパーさんは多いと思いますが、オリジナルの波形メモリ音源を搭載してみると良い感じかもしれませんよ。プログラミング知識は割と豊富なものの、音声プログラミングの知識ゼロの私にも作れたのだから、企業が本気になって作れば簡単に作れるんじゃないかと思います。

これは結構本気で思っています。
もちろん、懐ゲーをエミュレータで・・・ではなく、新作を。
(移植モノではそういう仕組みでやっても普通過ぎて面白くない)

実際、SUZUKI PLANの売上げは、海外売上高比率8割強(主に欧米)なので、海外メインで活動しているといっても過言ではありません。英語はそんなに得意ではありませんが、結構何とかなるものです。

そういえば、開発室Pixelさんの洞窟物語とかも、最初に海外で注目されたと思いますが、洞窟物語の音楽の仕組みも波形メモリ音源だったりします。(仕組み上、VGSとは違い、処理性能よりも表現性能を重視されているようなので、開発室Pixelさんの波形メモリ音源の方が、音楽としては良い感じのものが作れるという違いがありますが)

■効果的なアピールを

このような「独特な製品特性」を持っていることは、マーケティング(主にブランディング)をする上で、とても有利です。つまり、この製品特性をアピールしない手はありません。そこで、「VGSの音源でアレンジしたJ.S.Bachの平均律クラビーア曲集を作ろう」という神憑り的な発想に至った訳です。



え、東方じゃないの?



・・・そうです。

私は最初、東方ではなく、WTCで行こうと考えました。
WTC = Well Tempered Clavier(平均律)

実は、その残骸が残っています。

私のAndroidアプリの一覧をご確認ください。
https://play.google.com/store/apps/developer?id=SUZUKI+PLAN

SUZUKI PLANのAndroidアプリ一覧
(2014/1/10時点)

画面下部で一際目を引くJ.S.Bach大先生。

折角なので、もうちょっと拡大してみましょう。

デデーン!!!

このアプリのスクリーンショットを見ると、東方VGSと非常にソックリな事に気付くと思います・・・というより、東方VGSとほぼ同じです。(WTC1を流用して東方VGSを作ったので...ついでにいえば、画面上部のパネル部分は、NOKOGI RiderのMusic Roomからの流用ですw)
WTC1 on VGS(Lite)の画面
(東方VGSのパクリじゃありません)

結果的に、WTC1 on VGSは鳴かず飛ばずでした。

トータルのダウンロード数は、今のところ200件ぐらいです。完全無料のアプリで、リリースから半年以上経って200件というのは、逆にスゴイことかもしれません。なお、★5が2~3件ついていますが、内1件は私です。

私は、音楽的な部分のほぼ全てを、J.S.Bach先生から学びました。東方の音楽をアレンジするに当たっては、J.S.Bach大先生から学んだ知識(主に対位法)がかなり役に立ちました。正しく学びとれているかは別として。しかし、音楽に関しては素人同然の私でも、東方VGSで大きな評価を頂けたのは、J.S.Bachの力添えによるところがかなり大きいかもしれません。(もちろん、原作者であるZUNさんの力が一番大きいですが)

きっと、東方VGSの至る所に、J.S.Bachの息吹(?)を感じられるかも。

これから作曲や編曲の世界に足を踏み入れようとされる方は、J.S.Bachにどっぷり浸かることをオススメします。ちなみに、私のお気に入りの奏者は、月並みにGlenn Gouldです。あとは、Ton Koopmanとか。一応、私はインヴェンション全曲と平均律の途中(1,2番のプレリュードとフーガ)までは弾けました。もう弾かなくなってから結構経つので、今はサッパリですが。

インヴェンションは、バッハ流の作曲法を学習するための入門書として書かれた側面もある曲集なので、私の作曲や編曲の技術は、インヴェンションからの影響がかなり大きいです。ちなみに、お気に入りは2声の15番です。(フーガが好きなので)

■J.S.Bachから学んだこと

「J.S.Bachから学んだ」とは言っても、直接、J.S.Bachの師事を受けた訳ではありません。何故なら、私が生まれる遥か前に亡くなられていたので。しかし、仮にご存命だったとしても、私は、音楽を専門にやってきた訳ではないので、そういう機会は無かったのではないかと思います。

具体的にやった事は、「J.S.Bachの音楽を楽譜を見ながら聴く」ということです。
そして、音楽(モチーフ、各声部、声部間の因果関係など)を徹底的に解析(アナリーゼ)します。
アナリーゼの例
(青い丸で囲っている部分がモチーフ)

実際に鍵盤を使って演奏する事も、とても大切です。

なお、別に高価なグランドピアノとかじゃなくて、5000円ぐらいで買えるCasioのキーボードとかで大丈夫です。J.S.Bachの頃の鍵盤音楽は、チェンバロ(ピアノよりも音域が狭く強弱表現も無い楽器)用に作られたものばかりなので、49鍵(できれば61鍵)で十分演奏可能ですし、ベロシティーコントロール(強弱)も不要です。むしろ、ベロシティーコントロールはOFFに出来た方が良い感じかもしれません。当然ですが、ペダル(ダンパーペダル)とかも不要です。

(最初の内は)両手で弾く必要はありません。
また、装飾音とかも入れなくて良いです。

片手でモチーフの切れ目、形の変化、調性の変化などを意識しつつ、一定のテンポ(遅くてOK)で弾くことを意識すれば良いです。ただ、左手と右手のパートがどのような関係にあるか意識することは重要ですが。

片手での演奏を、左右それぞれ何百回、何千回と繰り返し、アナリーゼが完璧なものになる頃には、自然と両手で弾きつつ、バロック感のある装飾音も鳴らせるようになり、且つ、速いテンポで弾くこともできるようになります。(※私の経験談です)



「VGSの振り返り」ってよりは、「J.S.Bachのすゝめ」みたいな感じになってしまったなw
私の話しが脱線するのはいつものことです。



以下、広告です。


新品価格
¥2,277から
(2014/1/9 22:35時点)



新品価格
¥1,890から
(2014/1/10 11:38時点)


新品価格
¥32,900から
(2014/1/9 22:02時点)


2012年8月29日水曜日

波形メモリ音源(VGS)

拙作「SHOT04 - NOKOGI Rider」で採用している波形メモリ音源VGSについて、解説します。
まず、VGSという音源は、物理的には実在しません。
私の脳内で設計し、それをソフトウェア・エミュレーションする方式で、「SHOT04 - NOKOGI Rider」に搭載しました。

基本スペック:
・周波数: 22050Hz固定
・ビットレート: 16bit固定
・チャネル: モノラル固定
・同時発音: 6声
・音色数: 4(三角波、ノコギリ波、矩形波、ノイズ)
・声部別エンベロープ
・ピッチダウン(※ピッチアップは不要だったので未実装)
・声部別ボリューム
・マスターボリューム
・自動マスターボリューム制御(主にフェードアウト用途)

ちなみに、分解率=周波数という方式を採用。つまり、22050fpsです。
厳密には、処理周期は100ms間隔(10fps)ですが、オペレーションは22050fpsのフレーム間隔で出せます。
つまり、音の長さの最小は、だいたい45μ秒(1μ秒=100万分の1秒)程度の間隔になります。
テンポ120の場合、32768分音符がだいたい61μ秒になるので、「テンポ120の65536分音符よりちょっと長く、32768分音符よりちょっと短い」という感じです。

・・・少し分かり難いですね。
もう少し分かり易く例えるなら、報道によると東京証券取引所では、次期売買システムの取引性能を「1件あたり1ms以下にする(1秒間に1000件以上の取引ができるようにする)」らしいですが、そのシステムで「1回の取引をしている間に22回ぐらい音符を鳴らすことができる」という感じです。

一見すると誰得機能ですが、かなり重要な機能です。東証の方は誰が得するのか理解に苦しみますが。
この分解性能の粒度によって、音楽の表現性能が劇的に変わります。
この辺りのことは、音源本体(ハードウェア=エミュレータ)ではなく音源ドライバの役回りですが。

もちろん、音源ドライバも自作しました。
音源ドライバ仕様は、固定長のオペレーションで発音指示や待機指示をしたりする感じです。
昔のアーケードゲームとかだと、Z80で組むのが一般的。

VGSの場合、「何処からがハード仕様で、何処からがドライバ仕様なのか」がかなり曖昧ですが。
一応、一般的な区分は、「オペレーションを送るプログラム」がドライバで、「オペレーションを処理する部分(プログラム)」がハードウェア(エミュレータ)という風になります。
VGSの場合、ハードも論理的な存在だから、境界線が曖昧になります。
全てが論理的であれば、境界線の存在自体、ナンセンスだったりします。

そして、オペレーションの集まりが曲データになります。
ただ、オペレーションをずらずら並べて曲データを作るのが面倒なので、独自のMMLコンパイラ(MMLで書いたものをオペレーション集合に変換するプログラム)も作りました。

例えば、「SHOT04 - NOKOGI Rider」の「STAGE 1」のMMLは以下のような感じ。
$Brass \s600 \e22050 @1 %80
$Harp \s1000 \e1500 @0 %50
$Bass \s10   \e200 @2 %50
$Sq \s600 \e22050 @2 %75
$Sq2 \s6000 \e22050 @1 %80
$Hue \s5000 \e22050 @2 %80
$Osi \s22050 \e10000 @2 %80
$Ou \s500 \e5000 @1 %50

$B  \s10 \e1000 p-128 @0 %10 v35 o3
$S  \s1  \e1000 p-128 @3 %20 v20 o4

#-----------------------------------------------------------------------------
# Bass
#-----------------------------------------------------------------------------

Ch0 t172 m8 v12 (Bass) o3l16 |
Ch0 d8ddd8ddd8ddd8dd c8ccc8ccc8ccc8cc < b-8b-b-b-8b-b-b-8b-b-b-8b-b- a8aaa8aa aa>a<a>g<a>f<a
Ch0 l8 gggg gggg dddd dde-f gggg gggg ggrg16g16 gggg
Ch0 gggg gggg ff>f<f ff>f<f gg>g<g g16g16g>g<g g16g16g>g<g l16 <ffggaab-b-
Ch0 > crcccrcccrcccrcc drdddrdddrdddrdd grgggrgggrgggrgg frfffrfffrfffrff
Ch0 crcccrcccrcccrcc grgggrgggrgggrgg <g4.a4.b-4^2 l8 gg>g<g
Ch0 > l16 c8c4ccc8c8>c8<cc < g8g4ggg8g8>g8<gg f8f4fff8f8>f8<f8 > d8d8>d8<ddd8d8>d8<dd
Ch0 c8cc>c8<ccc8cc>c8<cc d8dd>d8<dd dd>d<d>c<db-d grgggrgggrgggrgg d8d4ddd4f+4
Ch0 l8 > dd>d<d4d>d<d < gg>g<g4g>g<g > cc>c<c4c>c<c dd>d<dcc>c<c
Ch0 dd4d16d16dd>d<d cc>c<c cc>c<c < aa>a<a4a>a<a aa>a<a4 a>a<a
Ch0 l8 > dd>d<d4d>d<d < gg>g<g4g>g<g > cc>c<c4c>c<c dd>d<dcc>c<c
Ch0 dd>d<d4d>d<d < aa>a<a4a>a<a > dd>d<d4d>d<d dd>d<d4ddd

#-----------------------------------------------------------------------------
# Melody
#-----------------------------------------------------------------------------

$Me1 r1r1r1r1 d2rdc<b- a2f4a4 g1^2r2 > d2rdc<b- >c2<a4>f4 d1^2r2
$Me2 e-2re-fg f2d4f4 g2rgab- a2g4f4 g2>c2< b-4a4g4a4 b-4.>c4.d4^2.r4
$Me3 (Sq) < e-2re-dc d2<b-2> c2rc<b-a g4b->d8^2 e-2re-fg f2d2 b-2rb-ag f+4a>c4.d4
$Me4 < a4gf8^2 b-4ag8^2 e4fg4efg a4.g16f16g4e4 d2ref4 g2rg>c4< a1^2.r4
$Me5 a4gf8^2 b-4ag8^2 e4fg4efg a4.g16f16g4e4 d2rdefec4<a4.>e4 d2.^16 l32 ef ga b->c d1

Ch1 v13 (Brass) \s3000 o5l8  (Me1)(Me2)  (Me3) (Brass) v-- (Me4)(Me5) v++
Ch2 v12 (Brass) \s6000 o4l8 <(Me1)(Me2)> (Me3) (Hue) > v- (Me4)(Me5)< v+

#-----------------------------------------------------------------------------
# Side-A
#-----------------------------------------------------------------------------
Ch3 v10(Ou)o4l16
Ch3 a>dfa<  v- a>dfa<  v- a>dfa<  v- a>dfa<  v+++
Ch3 g>ce-g< v- g>ce-g< v- g>ce-g< v- g>ce-g< v+++
Ch3 fb->df< v- fb->df< v- fb->df< v- fb->df< v+++
Ch3 < fa>cf v- a>cfa v- fc<af v- c<afc v+++

Ch3  grgr8.gggrgr8.gr
Ch3   drdr8.dddrdr8.dr
Ch3 (Sq) \s1000 > g4.fe-d2 <  @1 b-2g4b-4
Ch3 @2l8 b-2rb->cd f2rfa>c
Ch3 @1l16 \s50 g>d<db-<b->g<g>d<db-<b->g<g>d<db- \s1000
Ch3 @2g4.fga4b-4
Ch3 l2>ce-d<ab->dc1 <<g>cdg b-4.>c4.d4^2.r4
Ch3 (Ou)l8 e->e-ce-<g>e-ce- < d>d<b->d<g>d<b->d< c>c<a>c<f>c<a>c< gb->dg<gb->dg
Ch3 l16 c>c<g>c<e->c<g>c< c>c<g>c<e->c<g>c<
Ch3 < a>afadafa<a>afadafa<
Ch3 b->b-gb-db-gb-< b->b-gb-db-gb-<
Ch3 < df+a>c df+a>c df+a>c df+a>c

#-----------------------------------------------------------------------------
# Side-B
#-----------------------------------------------------------------------------
Ch4 v12\s100\e1000@2%65o5l1 # dc<b-a


Ch4 l32 v2  d>d< v+ d>d< v+ d>d< v+ d>d< d>d< v+ d>d< v+ d>d< v+ d>d< v+ d>d< v- d>d< v- d>d< v- d>d< d>d< v- d>d< v- d>d< v- d>d<
Ch4 l32 v2  c>c< v+ c>c< v+ c>c< v+ c>c< c>c< v+ c>c< v+ c>c< v+ c>c< v+ c>c< v- c>c< v- c>c< v- c>c< c>c< v- c>c< v- c>c< v- c>c<
Ch4 l32 v2< b->b-< v+ b->b-< v+ b->b-< v+ b->b-< b->b-< v+ b->b-< v+ b->b-< v+ b->b-< v+ b->b-< v- b->b-< v- b->b-< v- b->b-< b->b-< v- b->b-< v- b->b-< v- b->b-<
Ch4 l32 v2  a>a< v+ a>a< v+ a>a< v+ a>a< a>a< v+ a>a< v+ a>a< v+ a>a< v+ a>a< v- a>a< v- a>a< v- a>a< a>a< v- a>a< v- a>a< v- a>a<

Ch4 v9(Sq)l8 \s4000 v9 b-2rb-ag f2rfdf g1 d4.e-16f16g4b-4
Ch4 g2rgab- >c2.f4d1^2r2 l16
Ch4 \s1000 c<b->c4r8c2
Ch4 <a4.b->cd4f4
Ch4 g4.fe-d4<b-4 f2r2
Ch4 < g2>c2d2g2 >d2.^16l32 e-fgab->c d1 l8
Ch4 < v-- r32 e-2re-dc d2<b-2> c2rc<b-a g4b->d8^2 e-2re-fg f2d2 b-2rb-ag f+4a>c4.d8.^32 v++

#-----------------------------------------------------------------------------
# Side-A+B(C part)
#-----------------------------------------------------------------------------
$SI1 l8(Ou) dfa>d< dfa>d< dgb->d< dgb->d< ceg>c< ceg>c< <a>dfagec<g a>afadafa c>c<g>c<e>c<g>c< dfa>d< dfa>d< dfa>d< dfa>d<
$SI2        dfa>d< dfa>d< dgb->d< dgb->d< ceg>c< ceg>c< <a>dfagec<g d>d<a>d<f>d<a>d< c>c<a>c<e>c<a>c< dfa>d<dfa>d< dfa>dfa>d

Ch3 o4    v++ (SI1) (SI2) f8 v--
Ch4 o4    r16 (SI1) (SI2) f16

#-----------------------------------------------------------------------------
# Drums
#-----------------------------------------------------------------------------
Ch5 l4 (B) cccc cccc cccc ccc8 (S)c8c8c16c16
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c8c8
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)cccc
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c8c8
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c8 (S)ff (B) c8 (S)e-e- (B) c8 (S)d-d- (B) c8 (S)<bb>

Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c8c8
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)cccc
Ch5 (B) c2c2 (S)c8(B)c8c8 (S)c8(B)c8c8 (S)c8(B)c8
Ch5 (S) f4.d4.<b-4> (B)r2c8(S)c8c8cc

Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c8c8
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)c4
Ch5 l16 (B) c4 (S)c8.(B)c c8cc (S)cccc

Ch5 l8 (B)c(S)c(B)c(S)c(B)c(S)c(B)c(S)c
Ch5 l8 (B)c(S)c16c16(B)c(S)c(B)c(S)c16c16(B)c(S)c
Ch5 l8 (B)c(S)c(B)c(S)c(B)c(S)c(B)c(S)c
Ch5 l16 (B)c8(S)c8c8cc cccc cccc

Ch5 l8(B) cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)cc
Ch5 l8(B) cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4(S)ccc
Ch5 l8(B) cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)cc
Ch5 l8(B) cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c4c(S)c(B)c cc(S)c(B)c (S)cccc16c16
特殊な命令は、主にエンベロープ関連の以下3つぐらいで、あとは標準的な仕様だと思います。
・「\s」スタート・エンベロープ(音を鳴らし始めてからMAX音量になるまでの時間)
・「\e」エンド・エンベロープ(音を止めてから音量0に減るまでの時間)
・「%」キーオフ・タイミング(%50で4分音符を鳴らせば、8分のタイミングでキーオフ指令を出して、そこからエンド・エンベロープによる減衰が始まります)

音色数は少ないのですが、エンベロープさえ弄れれば表現の幅は無限大です。
だから、音色数はもっとも基本的な三角波、ノコギリ波、矩形波(+ノイズ)だけでも、割と困りません。
フレキシブルな波形変化については、波形メモリ音源やPSG音源の単音では不可能な部分(FM音源じゃないとできない特徴)ですが。一応、複数チャネルを使って音を重ねれば、多少の変化は得られます。

ただし、あまり重ねすぎると汚くなりますが。
絵の具と同じです。
だから、同時発生数を敢えて6声に制限しました。
6声ぐらいが一番キレイ。


2012年5月4日金曜日

VGS version up(1.01)

http://suzukiplan.blogspot.jp/2012/05/blog-post_476.html
上記記事の対策を施したVGSをアップしました。

InvaderBlockは昨日の内に早々とアップできたのですが、VGSの方は1曲追加して出したので、曲を作るのに時間が掛かり、予定(昨日中)よりも0.5日程度遅れましたが、ギリギリセーフか。

これで大往生に専念できる・・・と、思ったら、体験版を作成する作業をやらなければ・・・
しかし、コレ(大往生)が450円というのは、ちょっと微妙な気分。安過ぎる。
大往生なら700円だろうが、3000円だろうが買うつもりだったんですが。

課金アイテムを販売しているのが値段のカラクリ?
本体は激安or無料にして、課金アイテムで利益を得るという手法は、STGでは微妙な気がしますが。
課金でエキストラステージみたいなものが追加されるのなら買うかもしれませんが。

2012年5月3日木曜日

強制停止になる原因

ようやく、ソースが触れる環境に帰ってきました。
で、早速エラーレポートで報告されている事案の調査をしました。

ちなみに、落ちたクラス(VgeSurfaceView)のソースは↓のような感じ。
/*
*------------------------------------------------------------------------
* メインループ (スレッド)
*------------------------------------------------------------------------
*/
@Override
public void run() {
SurfaceHolder holder=getHolder();
Canvas canvas;
while (isAttached) {
// 仮想VRAMへの描画処理
PSGTEST.setVram(vram);
// 仮想VRAMを実VRAMへ転送
canvas=holder.lockCanvas();
canvas.drawBitmap(vram,vramRect,screenRect,screenPaint);
holder.unlockCanvasAndPost(canvas);
}
}

赤い網掛け部分がNullPointerExceptionが発生した部分。
なので、青い網掛け(lockCanvas)がnullを返したことが原因。

Android SDKのマニュアルを読んでいたら、妙な記述を発見。(以下、抜粋)
If you call this repeatedly when the Surface is not ready (before Callback.surfaceCreated or after Callback.surfaceDestroyed), your calls will be throttled to a slow rate in order to avoid consuming CPU.

上記を逆説すれば、「リトライは必要」ということ。
(ついでに、リトライ時にsleepをしなくてもハングにはならないらしい)

なので、以下のように修正すればOKかな。
Invader BlockとVGE Chiptune Musicの両方に下記の対策を入れて、本日中にリリース予定です。
public void run() {
SurfaceHolder holder=getHolder();
Canvas canvas;
while (isAttached) {
// 仮想VRAMへの描画処理
IBLOCK.setVram(vram);
// 仮想VRAMを実VRAMへ転送
canvas=holder.lockCanvas();
while(null==canvas && isAttached) canvas=holder.lockCanvas();
if(null==canvas) break;
canvas.drawBitmap(vram,vramRect,screenRect,screenPaint);
holder.unlockCanvasAndPost(canvas);
}
}
修正ポイント:
・リトライ要の場合、リトライ(Destroy時は中断して抜ける)
・リトライ中にDestroyになった場合はスレッド停止

久々にAndroidアプリ開発っぽい内容の記事でした。

初エラーレポート

VGS Chiptune musicがいつの間にやら100DL超えてました。
コメントを見る限り、私の音楽自体が好評みたいで、うれしい限りです。
ありがとうございます。

そして、初めてエラーレポートを1件頂きました。
Javaソース部分でSurfaceViewの使い方にマズイところがあるようです。
マズイですね、これは。
たぶん、Invader Blockの方にも同件の問題がありそう。
今日の夜には、調査&対策したいと思います。

本当は、今から即効で対策したいところですが、Javaソースの入った開発環境には夜にならないと触れない・・・お出かけ環境にJavaソースを持ってくるのを失念してました。ソースが無くてもある程度推理できますが。
・SurfaceViewのrunで落ちている(NullPointerException)
・SurfaceViewのrunでやっていること
 (1) VGEのグラフィック更新(JNI)→AndroidBitmap作成
 (2) Canvasをlockし、AndroidBitmapを書き込み、unlock
で、NullPointerExceptionになるということは、(2)に問題がある可能性が高い筈。
SurfaceHolder.getHolderで取得したホルダーのインスタンスを、スレッド生存中に使い回しているのがマズイのかな?(ソースを見ていないから、ハズレの可能性も高いですが)
 
しかし、ソースを難読化しなかったお陰で、Java部分でバグがあればすぐに分かって便利。
Javaソースは全体の1%に満たない(99%はCでできている)から、仮に解読されても問題ありません。

2012年3月24日土曜日

VGS Chiptune Music

「INVADER BLOCK 2」のリビジョンアップ作業に入る前に、折角作った独自音源ドライバなんだから、サンプルミュージックだけでも配っておこうと思い、Androidマーケットで無料配布しておきました。(本当は、8曲作って出そうとしてましたが、6曲のみですが...)
成果は、何かしらの形に残しておきたかったので。

アプリの名称は、「VGS Chiptune Music」(和名:VGS チップチューン音楽)。
「音楽&オーディオ」のカテゴリに流してます。
明日ぐらいには、Android Market(Google Play)で「suzukiplan」とかで検索してヒットする筈。
そういえば、有料アプリは開発者本人が買えない仕組みになっていますが、無料アプリはどうなっているんだろうか?無料アプリを公開するのは初めてなので、1回だけ試してみる予定。

これで、リビジョンアップ作業に入れます。


追記:(16:45頃)
もう公開されたようです。無料の方が反映が早いのかな。
自作アプリを自分でダウロードすることは、無料なら可能なようです。
FTPやSDカードで携帯電話にAPKを持っていく手間が省けて助かります。

あと、無料アプリだとAdMobで広告を打つことができるようです。(有料アプリだとできない)
やっぱり、無料で流して、アフィリエイトで収入を得るタイプじゃないとダメポですかね。

2012年3月20日火曜日

解析断念

ptcopの解析は断念。
調べれば何とかなりそうな感じでしたが、ピスコラで作り溜めた曲はせいぜい20曲ぐらいだし、MMLの打ち込みにもだいぶ慣れてきて、一日3~5曲程度ならアナログ方式(ピスコラのピアノロールを見ながらMMLを書き起こす)でできそうな感じなので、解析を完遂させる労力に見合わないと判断。(解析ができても、そこからMMLにデコードするのも面倒だし)

曲はとりあえず、5曲ほど、MML化しました。
8曲ぐらいできたら、無償でストアに流します。(たぶん)

2012年3月19日月曜日

ptcopを解析中...

ptcopファイルの音符情報等(EventV5レコード)の解析ですが・・・中々厄介だということは、把握。
ピスコラ自体、あまり「誰もが知っている」というレベルで普及しているものではないので、解析データの情報が転がっていない(海外にかなり間違ったデータを載せているものはありましたが...)から、色々と試行錯誤しながら解析しています。

とりあえず、かなり適当に作ったコンバータで、4部休符+4部音符(音程はc)を2小節(音符はオクターブ0と1を交互に)鳴らすptcopを解析したところ、こんな感じになりました。
Number of event: 25
    1: Tr#00/Ev#0C: Inst: 0000(0)
-----: Tr#00: Wait=01f0(496)
    2: Tr#00/Ev#02: Key : 6680(26240)
    3: Tr#00/Ev#01: Len : 01f0(496)
    4: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
    5: Tr#00/Ev#02: Key : 7e80(32384)
    6: Tr#00/Ev#01: Len : 01f0(496)
    7: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
    8: Tr#00/Ev#02: Key : 6680(26240)
    9: Tr#00/Ev#01: Len : 01f0(496)
   10: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
   11: Tr#00/Ev#02: Key : 7e80(32384)
   12: Tr#00/Ev#01: Len : 01f0(496)
   13: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
   14: Tr#00/Ev#02: Key : 6680(26240)
   15: Tr#00/Ev#01: Len : 01f0(496)
   16: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
   17: Tr#00/Ev#02: Key : 7e80(32384)
   18: Tr#00/Ev#01: Len : 01f0(496)
   19: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
   20: Tr#00/Ev#02: Key : 6680(26240)
   21: Tr#00/Ev#01: Len : 01f0(496)
   22: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=03e0(992)
   23: Tr#00/Ev#02: Key : 7e80(32384)
   24: Tr#00/Ev#01: Len : 01f0(496)
   25: Tr#00/Ev#04: Vel : 0068(104)
-----: Tr#00: Wait=6574(25972)


・・・ここまででもちょっと面倒でした。
しかし、まだ色々と読み違えている箇所があるようです。
なので、上記解析は未だ間違っているのかもしれません。
結構複雑です。

“V5”ということは、色々と仕様面で綺麗にはできていないだろう・・・と、想定済みですが。

2012年3月18日日曜日

色々と移植中

Android用の独自PSG音源は一応完成しましたが、実際に曲を打ち込んでみて、音源(またはMMLコンパイラ)のブラッシュアップを図る作業中。

私は、音楽の作曲にピストンコラージュを用いてますが、ピスコラのデータ形式(ptcop又はpttune)は公開されていないようなので、MMLに打ち込み直す作業に結構時間が掛かりました。
約50小説の曲でだいたい1人日ぐらい。(今日の昼ぐらいから作り始めて今1曲完成)

ノート(音符)データなら、MasterV5レコードEventV5レコード(ptcopの内部データ形式)あたりを解析すれば取り出せそうな感じなので、コンバータを作るのに丸1週間程度掛けても、余裕で元が取れるな・・・と、思い始めてます。

昔作った曲を~10曲程度作ったら、ジュークボックスみたいな形にして、Marketでタダで配る予定。
ちなみに、↓こういう曲ばかり。(ズンダラ節っていうんですかね?)
http://www.k2.dion.ne.jp/~ysuzuki/game06/bgm09.mp3
※上記は、ピスコラで作ったもの

2012年3月17日土曜日

独自PSG音源の実機検証

Android用に作っているPSG音源なのに、Android上で一回も鳴らしたことが無かった(Windowsでのみ確認していた)ので、Android向けにコンパイルして鳴らしてみました。

ちなみに、画面(Windows/Android共通)は下記のような感じです。

結果は良好。
当然ながら、鳴っている音の内容も全くWindows版と同じ。
ただ、ちょっと音が丸くなったかもしれません。
これはスピーカーの個体差かな。


動作はかなり軽快です。

このテスタをバックグラウンドでループ再生し続けた状態で、INVADER BLOCK 2を起動してみましたが、全く処理落ちせずに動作できました。CPU使用率にかなりの余裕があるので、デバッグ機(LenovoのIdea Pad 01)よりも遅い環境でも問題無いと思います。

多少の表現能力を犠牲にしてでも性能を追求した甲斐がありました。

Android用・独自PSG音源(VGS)の仕様

概ね、Android用・独自PSG音源の仕様が固まったので、纏めておきます。
  • 基本情報: 22050Hz + 16bit + モノラル(秒間約43キロバイト程度)
  • 同時発声: 6ch (6声)
  • 分解精度: 1/22050 (1Hz毎にキーオン等のイベント指令が可能)
  • 波形数: 4種類(三角波、ノコギリ波、短形波、 短形ノイズ)のプリセットのみ
  • エンベロープ:  各ch毎(6系統) & キーオン・キーオフ毎(2系統) に設定可能
  • ピッチシフト: 各ch毎に周波数精度の自動ピッチアップ・ピッチダウンに対応
  • ボリューム: マスターボリューム+チャネル別ボリューム
  • 処理性能: 500MHz程度のマシンで、CPUを最大2~3%占有する
  • 発音例:  http://www.k2.dion.ne.jp/~ysuzuki/sample2.mp3 (※ノイズとピッチシフトは未使用)
シンプル過ぎるぐらいシンプルですが、ゲーム音楽用の音源としてはこれぐらいが丁度良いです。

Android搭載用ということで、消費電力を気をつけなければいけないから、性能には拘りました。
普通、波形計算には浮動小数点数が使われるのですが、全て整数で計算したりとか。
なお、AndroidのAPIが全般的に浮動小数点数を多様するものが多いので、Android端末のCPU(ARM)は、FPUが特化しているのかな?・・・と思ったのですが、それ程でもなかったので、計算は全て整数で行うのが正解です。(単にAndroidIを作った人が性能に関して疎かっただけ)


ドラム音源

独自PSG音源のドラムは、完全にプリセットのPCMでいこうとしたのですが、自動的にキーダウン・キーアップする機能がやっぱり欲しかったので、ドラムもPSGで鳴らす方向で。

↓こんな感じになりました。
http://www.k2.dion.ne.jp/~ysuzuki/drum.mp3

まぁ、ショボイですが、この方がPSG音源とも調和が取れるので良いかも。
音源については、あとはループ再生する命令を実装すれば一通り完成。
ようやく、本編(ゲーム)の開発に戻れそうです。

そういえば、前作(INVADER BLOCK 2)ですが、マーケットでは意見を貰えるほどダウンロードされていないので、会社の人や取引先の人から意見を収集したところ、主に以下のような指摘がありました。

①難しすぎる
②残機が欲しい(1機でゲームオーバーという仕様)
③何故、Android 2.2対応にしなかったし

これでもかなり難度を落としたのですが、まだまだのようです。
②は単純に①の影響で1回のプレイ時間が満足のいくものでないことが原因だと思います。
ということで、難易度が一番のネック。

でも、易し過ぎると私が遊べなくなってしまいます。
という訳で、次回作ではEasy/Normal/Hardみたいな感じのランク設定を設ける予定。
たぶん、私が作るゲームでは初めての試みになる筈。
一応、昔作ったSHOT02というゲームにエキスパート・モードみたいなものがありましたが。


あと、取引先の人のAndroidが2.2でした。
やはり、2.2の普及率は侮れない。
でも、2.3.3以降にしないとOpenSLが使えないからどうにもなりません。
OpenSLじゃないと、波形データを直書きできないので。
波形データを直書きできないということは、(音関係では)何もできないも同然。

2012年3月15日木曜日

脳内で鳴っていた筈の音

昨日、独自PSG音源で鳴らしたサンプルをアップしていたのですが、実の所、MMLで書いた内容と微妙に違ってて、違和感みたいなものを感じていました。

「まぁ、こんなもんだろ」程度に思っていたのですが、実は、MMLコンパイラがバグっていて、本来、各チャネルに設定できる筈のエンベロープが、全てチャネル0にしか設定されず、チャネル1~5はデフォルトのエンベロープで鳴っていた・・・という、かなりしょっぱいバグでした。

正しい演奏は、下記。
http://www.k2.dion.ne.jp/~ysuzuki/sample2.mp3

昨日アップロードしたしょっぱいヤツは、下記。
http://www.k2.dion.ne.jp/~ysuzuki/sample1.mp3

何故、昨日の時点で耳で気付けなかったのか・・・。
作曲や音楽は完全に専門外ですが、それにしては酷いイージーミスです。

2012年3月14日水曜日

独自音源の実力(当社比)

とりあえず、独自PSG音源で音楽らしい音楽を鳴らせるようになったのに、「蛙の歌」や「キラキラ星」などの童謡しか鳴らさないのはどうよ?・・・という訳で、自作の曲で現状の独自PSG音源の実力を100%発揮した音楽を作ってみました。

http://www.k2.dion.ne.jp/~ysuzuki/sample1.mp3

現状、ドラム機能がないので、ドラムの無い曲。
新曲ではなく、1年ぐらい前にピスコラで作った曲ですが。
とりあえず、6チャンネル全て使って鳴らしています。

とりあえず、これが現状の音源の表現性能の限界・・・という訳ではないですが。
作曲の腕前がイマイチなので、表現性能としては限界値に達せません。
実装した機能を全て使っているので、機能的な限界なのは確かですが。

次の課題は、ドラム音源の搭載。
とりあえず、申し訳ない程度のノイズ音源を実装してみましたが、やはりキーダウンとか、性能影響がありそうな機能追加が必要になってしまうので、やはり、PCMをそのまま鳴らす方向がベストか。

デューティー比は落とす

ここ数日、独自PSG音源エミュレータを作成する方向で作業をしていましたが、ちょっと転機。

当初、波形は「三角波」、「ノコギリ波」、「短形波」の3種類で、デューティー比を弄れる感じにしようと思ったのですが、基本周波数が22050Hzだとあまり綺麗な音が鳴らなかったので、デューティー比は5:5固定にします。

そうなると、独自PSG音源は、PSG音源ではなく、独自の波形メモリ音源になるのかな?
少なくとも、波形に関してはプログラマブルではなく、完全固定になるので。
そもそも、私は「PSG音源」の厳密な定義はよく分かっていませんが。
「プログラムで弄り易い音源」という意味なら、波形メモリ音源もPSGの一種のような気もする。

ちなみに、デューティー比というのは、波形の正負値の比率のことです。

例:デューティー比5:5の正弦波

で、この比率を変えると、音色が「かなり」変化します。
波形エディタで書いて鳴らしてみると、楽しいかもしれません。
波形エディタは、下記URLにある「効果音エディタ_D」というのがオススメ。
http://www.geocities.jp/hirogamesoft/se_d/se_d.html



デューティー比が弄れれば、波形パターン(音色数)が少なくても、色々な音色が作れます...
なので、性能のためとはいえ、ちょっと残念かも。
遅くとも600MHz程度の超高速なCPUを積んでいるAndroid端末なら、全然気にならないレベルなんですが、CPU占有が多すぎると消費電力量が多くなってしまうので、やはり、性能を一番気にしておきたいところ。

2012年3月13日火曜日

合成完成

前の記事に書いたとおりのアルゴリズムで、音符の合成ロジックを作ってみたところ、アッサリと合成処理が完成。

プログラムを書くのより、サンプルの演奏データを作る方が時間が掛かったかも。
とりあえず、↓こんな感じ。
http://www.k2.dion.ne.jp/~ysuzuki/seikou4.mp3

ようやく、音楽らしい音楽を鳴らせるところまできました。
あとは、MMLで色々と細かいけど重要な機能を色々追加すれば、音源機能はとりあえず完成かな。
当初、ノイズ音源も作ろうとしましたが、ノイズ(ドラム)はPCMの固定波形パターンを鳴らせば良いんじゃないかと、思い始めました。(その方が、処理が軽いので)

いっぺんにやろうとするから難しい

独自PSG音源専用のMMLコンパイラで、とりあえず、1チャネルで音楽を鳴らすことに成功。
毎日だいたい夜11:00頃帰宅(これでも早いほう)なので、ウィークデーの進捗はこの程度。
次の課題は「複数チャネルの音をどうやって同時に鳴らすか」。

まぁ、その辺は簡単に計算できます。
今のところ、PSG音源に対する指示情報としては、以下の7種類。

  1. エンベロープ1を設定(キーオンしてから100%になるまでの周波数)
  2. エンベロープ2を設定(オーオフしてから消音になるまでの周波数)
  3. チャネル別のボリュームを設定
  4. マスターボリュームを設定
  5. キーオン(音を鳴らす指示)※音色や音程も一緒に指定する仕様
  6. キーオフ(音を止める指示)
  7. 待機

網掛けしている待機という指示情報だけに着眼すれば良いだけです。

仮に、
  • Ch.1: event1 → wait(100Hz) → event2
  • Ch.2: event3 → wait(50Hz) → event4 → wait(75Hz) → event5
という感じで並んでいたら、

event1 → event3 → wait(50Hz) → event4 → wait(50hz) → event2 → wait(25Hz) → event5

という感じにすればOK。

アルゴリズム的に表現すれば、

  1. 待機時間が短い方の待機時間を採用し、
  2. 長い方(非採用)の待機時間は、採用値を減算
  3. 次の待機時間についても同じ処理で求める

で、OKな筈。(未検証)

処理としては単純。
問題は6チャネルの場合、フラグが沢山有り過ぎて、アルゴリズムが無茶苦茶複雑になりそうだ・・・
と、思っていたのですが、ピンポン録音の要領で、

  1. チャネル1+チャネル2=チャネルA
  2. チャネルA+チャネル3=チャネルB
  3. チャネルB+チャネル4=チャネルC
  4. チャネルC+チャネル5=チャネルD
  5. チャネルD+チャネル6=チャネルE

って、やれば良いだけですね。
物凄く簡単だった。

これなら、明日にはチャネル合成ができるかな。(本業の状況次第ですが)

ちなみに、チャネル毎の音の合成(音源レベルの話)をどうやるのか疑問だったのですが、これは単純な足し算でOKでした。音の合成ってこんな簡単だったのか。(てっきり、もっと複雑な「xxxの公式」みたいなヤツでも要るのかと)

2012年3月11日日曜日

構文解析まではできた

独自PSG音源エミュレータで音楽を鳴らすためのMMLコンパイラを作成中。
本当は、この土日で完成させる予定でしたが、昨日、スマートフォンを買ったり、色々と設定やらをしたり、遊んでいたところ、完成しなかった・・・orz

とりあえず、今日の昼から開発を再開して、構文解析まではほぼ完成。
ただ、色々と細かい所ができてないです。

構文仕様としては、下図のような感じになりました。(色々足りないかも)

ごく簡単なマクロ言語です。
「$なにがし」でマクロを定義して、「Ch0~5」でチャネル毎の音符情報を書きます。

分解性能を周波数と同値にしたお陰で、「%」というオペランドを使って、音の長さに対するキーオンの時間の割合というものを定義できました(これがやりたかった)。%を低めに設定すればスタッカートみたいな感じになり、高めに設定すればレガートになる感じです。

ちなみに、ボリューム(音量)としては、マスターボリューム(全チャネル共通のボリューム)とチャネル別のボリュームのみで、ヴェロシティ(音符単位のボリューム)は無い仕様にしました。
できなくもないけど、私が作る曲では概ね要りません。
必要な時は、MIDIからの変換ツールの方でボリュームオペランド(v)で調整すれば良いし。
ただ、それだとデータ量が多くなってしまうので、改善の余地ありかもしれませんが、今のところ、多彩なヴェロシティの曲を作るつもりは無いというのが一番の理由。)
一応、データ的にはヴェロシティーに対応させる空き領域は有りますが。

2012年3月7日水曜日

性能良好

作成した自作PSG音源エミュレータ+ドライバでベンチマークをしてみました。
あんまり厳密な解析じゃないけど。

ちなみに測定環境は、

  • 型式:Acer AspireRevo R3610
  • CPU:Atom330 / 1.6GHz / 64Bit
  • メモリー:4GB

という、環境。
CPUに関しては、性能の悪さに定評のあるAtom。

この環境で開発もやっているから、Android用のコンパイルには物凄く時間が掛かります。
ですが、ベンチマーク用としては妥当です。
グラフィック(GPU)性能がちょっと良すぎる点がアレですが。

まず、VG-Engine(グラフィックのみ)でプロセスを起動した場合、CPU使用率は約5%前後。
で、VG-Sound(と、命名したオリジナルPSG音源エミュレータ)で、6ch同時に発音した状態で測定したところ、CPU使用率は概ね約7~8%前後。

ちょっとだけ、上がってしまいました。
ですが、この程度であれば、Android上でもサクサク動けます。(多分)

かなり、性能面には気をつけました。主に、

  • パイプラインハザードの防止
  • 浮動小数点は使わない
あたり。

前者は単純に分岐回数を可能な限り少なくするだけ。
(ループ値は論理積を使うなど)

後者は、本当に性能upに寄与するか、ケースバイケース。
例えば、エンベロープの計算に百分率が必須ですが、百分率を整数のみで計算する場合、
  • 割られる数×100 ÷ 割る数 = p(100%なら100)
  • n×p÷100 = nのp%の値
という感じで計算します。
※ここでは説明をし易くするために百分率といってますが、 実際は128分率とか64分率などで計算するのが一般的

FPUが高性能な場合、全ての数値を浮動小数点数で計算すれば、結果的には浮動小数点数のみで計算した方が命令の実行ステップが少ない分、高速になる可能性があります。ただ、実数は精度が悪い(表現できない数が多い)ので、「全てを浮動小数点数で」という部分がネック。音の場合、波形データは整数(16bitの2の補数)だから、FPUが早くても整数・実数間の変換がボトルネックになるし、パイプラインハザードは極力実装レベルでも防いでいるからステップ数はあまり問題にならない筈だ・・・

ということを悶々と考えた結果、実数を排除するのがベストと判断。
(単純に、実数がキライだというのもあります)

結果、Windowsではそこそこ良い性能結果だったので、読みは当ったんだろうと、思っておきます。
Androidでも同じ結果になるかは、定かではないですが。

音源ドライバ完成

週末は、MMLコンパイラを作る作業に専念したいため、前記事の分解率の問題を平日中に直してしまおう・・・と、思い昨夜、AM2:00ぐらいまで頑張っていたら、今日会社でグロッキー状態でした。
30を過ぎると、2時寝・6時起きはキツイ。

その甲斐あって、無事、音源ドライバ部分も完成。
以下のような感じで発音(KEYON)や消音(KEYOFF)などの指示情報をズラズラ並べれば・・・



↓こんな感じで演奏してくれます。
http://www.k2.dion.ne.jp/~ysuzuki/seikou3.mp3

若干、音程が切り替わる間のプツッという部分が気になります。
こういう風になる原因は、音が切り替わった時の直前の波形からの差異が大きいため。

パッと考え付く限り、回避する手段は、

  • 消音のエンベロープ時間を短くし、キーオフの待ち時間中に波形相異0で安定させる
  • キー切り替え時に近似値を算出し、乖離を少なくする

あたりかな。

前者は、MMLコンパイラで回避でき、後者はアルゴリズムで回避。
どっちが良いのかが、よく分からない。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...