musicLineアプリ開発日記

作曲を誰でも楽しく簡単に♪

Webで聴く!MIDIプレイヤーの実装

今回はWebで快適にMIDIを再生する話。
WebでのMIDI再生は動作が重かったので、MP3に変換して再生しました。

プレイヤー動作



はじめに

musicLineでは、コミュニティでユーザーの投稿した曲を再生できます。
またコミュニティ曲のURLを共有して、他のユーザーに曲を勧めることができます。
しかし、musicLineのアプリを持ってないユーザーは曲を聴くことができず、Playストアに飛ぶようになっています。
もちろんPlayストアでアプリをインストールすると良いですが、そこまでしないと曲を聴けないです😅
そこまでして欲しいと願っていますが。。そもそもiOSはアプリすらまだないです😭

他の方法として共有動画を作成することもできますが、それもちょっと気軽に勧めたいって場合にはレンダリング時間が気になるところです。
それでもXで共有動画で曲を紹介してくれている mL民 に感謝😆✨

なのでもっと気軽に、アプリを超えて、曲を共有することを目指して、
WebでmusicLineコミュニティ内の曲を再生できるようにしました。



実装

WebでのMIDI再生の課題

はじめにWeb(Javascript)で動作するMIDIプレイヤーのライブラリを試してみました。
サーバーからMIDIファイルをDLして、Javascriptで再生するシンプルな実装だったのですが、

  • 再生処理が重くて音が途切れる
    特にモバイルでの動作時は止まることが多い
  • コミュニティの音と大きく異なる
    そもそもサウンドフォント(sf2)が使えない

の課題がありました。

そのため、MIDIファイルを一度音楽ファイル(WAVやMP3)に変換してから、再生する方法に変更しました。


MIDIファイルを音楽ファイルに変換

サーバーから直接MIDIファイルをDLせずに、サーバー(Ruby)で音楽ファイルに変換してDLします。
MIDIからWAVへの変換はFluidSynthを使いました。さらにWAVからMP3への変換にFFmpegを使っています。

この変換する時間はどうしても数十秒は掛かってしまうので、変換したMP3はしばらくキャッシュします。キャッシュしたMP3を使うことで、次訪れるユーザーはすぐに再生できます。
そのため、WAVファイルのままDLしても再生できますが、キャッシュサイズを小さくしたかったので、MP3に圧縮しています。

以上でWebでのMIDI再生の課題が解決できました。

こちらの方法でもWebにアクセスする最初の人はファイルを変換する時間を待たなければいけない問題はあります。
でもアプリをインストールしないと曲を聴けないよりは良いですねえ。


Herokuに外部ライブラリをインポート

より専門的な話になりますが、musicLineのサーバーにFluidSynthライブラリを取り入れるところにも課題があったので紹介します。
musicLineのサーバーはHerokuを使っています。そのため、Herokuの環境下に外部ライブラリを構築する必要があります。FFmpegはHerokuの拡張機能で簡単に取り込みができましたが、FluidSynth拡張機能のBuildPackが用意されていないため、自分でカスタムBuildPackを作る必要がありました。

ちなみに、違う方法(DockerContainerを使った方法)でも環境構築ができるので、こちらも試してみましたがこの方法は辞めました。
ローカルで仮想サーバーを試すときにはDockerContainerを使っているので、そのままHerokuの環境に適用できれば便利だと考えたのですが、

  • 他のBuildPackも使えなくなる
    Herokuが用意しているBuildPackも自分で環境を整えなければならない
  • デプロイ(環境構築)が遅い
    デプロイの際にキャッシュ等を使って最適化されているそう

ということがあり、Herokuを使う利点が失われると思い辞めました。

カスタムBuildPack

devcenter.heroku.com
このページを参考に作ります。
以下の3ファイル作る必要があるのですが、compileファイル以外は他のBuildPackと同じファイルを使って良さそうです。

  • detect​: この buildpack がアプリに適用するか判定
  • compile​: アプリで変換手順を実行するために使用
  • release​: メタデータをランタイムに戻す

compileファイルでライブラリのソースをDL・インストールする処理を記載します。
C++のソースをコンパイル・リンクして、環境変数を設定しています。
なかなか難しい部分でしたが、CMAKE等のC++ビルドツールに使い慣れていれば簡単だったかもしれません。
普段なにげに使っているapt-get等のパッケージ管理ツールはとても便利なんだと思い知らされました。

#!/bin/sh 

BUILD_DIR=$1
CACHE_DIR=$2

# midi->wavへ変換する依存ライブラリlibsndfileをインストール
LIBSND_CACHE_DIR=$CACHE_DIR/libsnd
LIBSND_DIR=$BUILD_DIR/vendor/libsnd

# $LIBSND_CACHE_DIR が存在する時キャッシュを使用
if [ ! -d "$LIBSND_CACHE_DIR" ]; then
    echo "-----> Installing libsndfile"

    LIBSND_SRC_DIR=/tmp/libsnd
    SND_URL="http://www.mega-nerd.com/libsndfile/files/libsndfile-1.0.28.tar.gz"

    mkdir -p $LIBSND_SRC_DIR
    curl -L $SND_URL | tar xz -C $LIBSND_SRC_DIR --strip-components=1

    mkdir -p $LIBSND_CACHE_DIR

    cd $LIBSND_SRC_DIR || return
    ./configure --prefix=$LIBSND_CACHE_DIR
    make
    make install
    echo "-----> libsndfile installation complete"
else
    echo "-----> libsndfile use cache"
fi

mkdir -p $LIBSND_DIR
cp -r $LIBSND_CACHE_DIR/* $LIBSND_DIR


# fluidsynthをインストール
FLUIDSYNTH_CACHE_DIR=$CACHE_DIR/fluidsynth
FLUIDSYNTH_DIR=$BUILD_DIR/vendor/fluidsynth

# $FLUIDSYNTH_CACHE_DIR  が存在する時キャッシュを使用
if [ ! -d "$FLUIDSYNTH_CACHE_DIR" ]; then
    echo "-----> Installing Fluidsynth"

    # FLUIDSYNTH_VERSION="2.3.5"
    FLUIDSYNTH_SRC_DIR=/tmp/fluidsynth
    FLUIDSYNTH_VERSION="2.1.7"
    FLUIDSYNTH_URL="https://github.com/FluidSynth/fluidsynth/archive/refs/tags/v$FLUIDSYNTH_VERSION.tar.gz"

    mkdir -p $FLUIDSYNTH_SRC_DIR
    curl -L $FLUIDSYNTH_URL | tar xz -C $FLUIDSYNTH_SRC_DIR --strip-components=1

    FLUIDSYNTH_BUILD_DIR=$FLUIDSYNTH_SRC_DIR/build
    mkdir $FLUIDSYNTH_BUILD_DIR

    mkdir -p $FLUIDSYNTH_CACHE_DIR

    cd $FLUIDSYNTH_BUILD_DIR || return
    cmake .. -Denable-libsndfile=ON  -DCMAKE_PREFIX_PATH=$LIBSND_DIR
    make
    make install DESTDIR=$FLUIDSYNTH_CACHE_DIR
    echo "-----> Fluidsynth installation complete"
else
    echo "-----> Fluidsynth use cache"
fi

mkdir -p $FLUIDSYNTH_DIR
cp -r $FLUIDSYNTH_CACHE_DIR/* $FLUIDSYNTH_DIR


# 環境変数の追加
mkdir -p $BUILD_DIR/.profile.d
echo "export PATH=\$PATH:$HOME/vendor/fluidsynth/usr/local/bin:$HOME/vendor/libsnd/bin" > $BUILD_DIR/.profile.d/fluidsynth.sh
echo "export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:$HOME/vendor/fluidsynth/usr/local/lib:$HOME/vendor/fluidsynth/usr/local/lib64:$HOME/vendor/libsnd/lib" >> $BUILD_DIR/.profile.d/fluidsynth.sh



おわりに

今回はWebでMIDIを再生する際に、再生を最適化するためにMP3に変換して再生しました。
WebでMIDIをそのまま再生すると処理が重くモバイルだとまともに再生されないことが誤算でしたが、MP3に変換することでなんとかWebでも再生することができました。
ちなみに同じサウンドフォントを使ってますが、音響ライブラリがアプリと異なるため、音も少し変わります😅

このURLでmusicLineを持っていなければ、Webプレイヤーに移ります。
https://3musicline.com/community/176751
(musicLineを持っていれば、アプリを開きコミュニティに移ります。)

https://3musicline.com/player/176751
(musicLineを持ってるユーザーはこちらのURLでWebプレイヤーを閲覧できます。)

実装の部分は試行錯誤した内容をごちゃごちゃと書いてしまいましたが、試したことを忘れないように備忘録として残しておきます。

ちなみに、最初にアクセスしたユーザーはMP3に変換する時間を待ってもらう必要があります。 頻繁にWebプレイヤーを使うユーザーはアプリをインストールして欲しいですね♪

なので待っている時間はアプリインストールを促す画面を出すようにしています。
ちゃっかり😋

アプリインストール促す画面


がちゃ/Gacyaさんインタビュー

mL民のインタビュー企画第3弾、ラスト(4人目)のインタビューです。
(インタビュー企画通算で13人目です!)
※mL民:作曲アプリmusicLineユーザーのこと
(「」タグで他の方の紹介も見れます☆)

インタビュー企画第3弾はmusicLine10周年記念の作曲コンテストで上位だった4名の方を紹介します。
最後は、一般部門1位の がちゃ/Gacyaさん です。

DMでのやり取りをインタビュー形式にまとめました。


スー

それでは、がちゃさんよろしくお願いします。

今回は囲むんだね
まあ最後だからみんなで
楽しみだな~


では最初にユーザーネームの由来はなんですか?


がちゃ

名前の由来は、
 …特にないんですけど()
友達に呼ばれてるあだ名を少しかえてがちゃにしました(笑)


スー

なるほど
あだ名が由来になったパターンですね!

由来なんてそんなもん
なんか可愛いじゃん♪

爽やかなアイコンだな~

うん、爽やかな気分になる😮



次にひとこと自己紹介をお願いします。


がちゃ

趣味はドラムを叩くことです!!
8、9年ぐらいやってます!
(その割にそんな上手くない)


スー

そんなに前からドラムをされているんですね!

何事も長く続けることが大事
とかいって上手いんでしょ
そんなあなたにアイスあげる
(え、アイス?


ドラムは部活とかバンド活動とかでされてるんですか?


がちゃ

吹奏楽部でパーカッションやってます!
バンド活動はやってないです~


スー

そうなんですね!
パーカッションならドラム以外も色々って感じですね♪

mL民はなんか吹部のイメージあるな
打ち込み作曲はバンド向けじゃないのかも


ちなみに、ドラム叩く曲で得意な曲や好きな曲はありますか?


がちゃ

Vaundyの怪獣の花唄が好きです!!
叩いててすごく気持ちいいので!


スー

いいですね~😄

www.youtube.com

疾走感がいい
ドラム叩くの気持ち良さそう
曇天の中のチャリが最高

ああ、MVの感じね✨
走り出さなきゃって気持ちになるな~🙂


次はSNSで応募があった質問ですが、好きなアニメを教えて欲しいです!


がちゃ

僕あんまりアニメ見なくて…
でも鬼滅の刃とかは好きですね(*-ω-)


スー

鬼滅の刃はかなり話題になりましたね~♪
もちろん僕もはまりました😊

また映画化もするみたいで勢いが凄い~

参照ページ 「鬼滅の刃」公式ポータルサイト

なんか鬼と戦う話だよねー
鬼を滅する刃だからね
そうそう、駆逐してやるってやつな
それ進撃の巨人だよ

。。そうだっけ~


でもアニメはあんまり見ないんですね~😮
他に好きなこととか楽しみにしてることはありますか?


がちゃ

最近は「Theo Town」ていうゲームにハマってます~
あとは曲聞くことぐらいしか好きなことないですね()


スー

ぽちぽちぽちっと、検索〜☆

TheoTown - Google Play のアプリ


都市開発シミュレーションゲーム
やっぱり創作系のゲームが好きなんですね😊

きた!シムシティ
Theo Townだけどね~
マインクラフトもおすすめ


まあ基本は NO MUSIC, NO LIFE!ってことですね😁
曲を聴くのも、探すことも楽しいですよね♪


次の質問ですが、作曲活動をしていて楽しいと思う時はどんなときですか?


がちゃ

曲が完成した時は達成感とかもあってすごい楽しいです!!


スー

そうですか〜♫
素敵な曲を作られていますから、達成感もすごくありそうです!

たしかに~
結局は完成した時が一番楽しいんだよな
その気持ちをいつまでも大切に
飽き性のアゴォーにそのまま返すよ


あと、がちゃさんはコラボやmLグループ「虹色コード」で活動されてたりしますが、共同で作曲することでの魅力について教えてください。


がちゃ

誰かと一緒に作ると、自分にない展開の仕方や楽器の使い方とか、いろいろ学べるので良いですよ!


スー

たしかに一緒に作ると気づきがあって学べそうですね😃

コラボとか楽しそうだし
モチベーションも上がりそう
え、オレは一人でいいや


今度アイスおごるよ
まあ一緒に作曲するのもありだな

もう少しコラボを手軽にできたらいいな



続いて、作曲する際に心がけていることはありますか?


がちゃ

色々あるんですけど
一番大切にしてるのはバランスですね
伴奏がメロディを邪魔してないかとか
結構意識してます…!


スー

バランスを意識するのも大事なんですね!
確かに、せっかくの良いメロディーが伴奏に埋もれたりしたらもったいないですもんね!

そっかーその辺りを意識するんだね
伴奏が邪魔にならないようにか
そんなあなたにアイスあげる

そのコメントは邪魔になってない?
そ、そうかあ


他にも細かい心がけもいっぱいあると思います。
今回10周年コンテストではそんながちゃさんの曲作りがみんなに響いた結果だと思います✨
本当におめでとうございます!!

コンテスト曲のワクワク感はすごかったです。
この記念日を大切にこれからも頑張れそうです😁

がちゃ/𝑮𝒂𝒄𝒚𝒂「星音【ML10周年記念】」

https://3musicline.com/community/176751 (アプリリンク)

こんな曲書きたいな
作れたら熱中するかも
がちゃの作り方って曲で教えてくれてるよ

ぜひ作り方聞きたいな
おれもー


では、曲の作り方教えてください😊

だから教えてくれてるよ

え?
え?じゃなーい


がちゃ

僕は大体コード進行を一番最初に作りますね(*-ω-)
それこそ星音もそうですし、コード進行を知ってからはずっとそうですね()
なのでメロディとかは頭のどっかからひねり出してます👍(?)


スー

コード進行か~
曲の設計図的な役割がありますよね🙄
適切にコード進行を設定できると、良い感じの曲ができるってことですね🤔
伝授ありがとうございます!

詳細はがちゃの作り方も見てね
頭ではわかってるんだけどな~
なかなか知識ないと使いこなせないね

じゃコード進行が良い感じになる機能つけたら
それだ
簡単に言わないで


次の目標ができたね😄
今後のmusicLineも楽しみだ~♪


ところで、がちゃさんの今の目標はなんですか?


がちゃ

目標はいろんな人の耳に留まる曲を作ることです!!


スー

素敵ですが、もう色んな人の耳に留まっていると思いますよ〜

でも、もっとたくさんの方に聞いていただきたいと僕も思っているので、これからも応援しています!


では最後に、みなさんに聴いてもらいたい自分のオリジナル曲名を教えてください


がちゃ

ジュピター聴いてもらいたいです!!


スー

ジュピターいい曲ですね!

がちゃ/𝑮𝒂𝒄𝒚𝒂「ジュピター」

https://3musicline.com/community/138323 (アプリリンク)

カリンバアルペジオも効果的で、宇宙感がありますね。
そしてドラマーと知ってから聞くとさすがドラムがかっこいいと思いました!
みなさんもぜひ聞いてみてください☆

がちゃさんありがとうございました!
これで今回のインタビュー企画はおしまいです!


また次の企画(インタビュー以外でもSNSの企画など)のアイデア募集中なので思いついた方はDMよろしくお願いします〜

X musicLine公式PRアカウント


インタビュー



挿絵のLINEスタンプ


ぬんさんインタビュー

mL民のインタビュー企画第3弾、3人目のインタビューです。
(インタビュー企画通算で12人目です!)
※mL民:作曲アプリmusicLineユーザーのこと
(「」タグで他の方の紹介も見れます☆)

インタビュー企画第3弾はmusicLine10周年記念の作曲コンテストで上位だった4名の方を紹介します。
3人目は、一般部門2位の ぬんさん です。

DMでのやり取りをインタビュー形式にまとめました。


スー

それではぬんさん、よろしくお願いします。
まずユーザーネームの由来はなんですか?


ぬん

特に大した由来はないですが、ぬんをローマ字表記に変換した時にnunとなるのがなんか可愛くてこれにしました。さらに2文字だと覚えてもらいやすいからという理由もあります。


スー

そうだったんですか!
。。確かにちょっとかわいい?🙄


でも覚えてもらいやすいのは大事ですね!


アゴォー

もう☆スーはわかってないなあ
nun はなんか可愛いんだよ~~



..じゃあわかった!!

この可愛さに気づいて☆



え、なにが?

だ・か・ら~~





だよ



スー

。。。

あ、そういうこと😲
nunって
目を隠して恥ずかしがっているような顔文字に見えて可愛いってことか


いや、考えすぎだろ
なんか可愛いに理由なんてないよ

まだ出てこないでって
後でちゃんと紹介するから


。。。😒


アゴォー

そうそう、この子はぬんさんの考えたキャラ?


ぬん

そうです!ただ僕は人を描くことが苦手なので、マント、シルクハット、手袋、雑な楕円形目玉で誤魔化しています。
キャラデザは僕の大好きなゲーム『星のカービィWii 』に登場するマホロアというキャラクターからめちゃくちゃ影響を受けてると思いますー


アゴォー

ぺちゃぺちゃぺちゃちゃっと

あれ、変な音してる?
そお?タッチ音なんてこんなもんだろ


マホロア | カービィWiki | Fandom

なるほど
ぬんさんのキャラもカービィの世界観に合いそう


スー

好きな世界観に合ったマイキャラを作りたいって気持ちわかります!

そうなんですか?
人も上手に描きそうですけど~
でも苦手な事を誤魔化す技術、大事ですね😄
なんでも得意なんて無いですもんね!

では次に、自己紹介をお願いします。


ぬん

みなさんこんにちは、ぬんです。
趣味はピアノを弾くことで、少し前まではゲームも遊んでいましたが最近は作曲かピアノの2択で音楽一色になりました。 ゲームはもう一年ほど手をつけていません。
学校での勉強がピンチです。


スー

すごい音楽漬けの毎日ですね!
ゲームしないなんて考えられない😨

ピアノが趣味なんですね♪
ピアノで弾く好きな曲はありますか?


ぬん

クラシックよりかはゲーム音楽を中心に自分の弾きたい曲を自由に弾いてますね。
最近ではマリオオデッセイの『Jump Up, Super Star! 』という曲をよく弾いてます!
楽しい気分になれます。


スー

ゲーム音楽も弾いているとは
親しみもてます😊

www.youtube.com

マリオオデッセイの曲とてもノリノリで良いですよね~♪
でもピアノで弾くとなると難しそう😮


あと、musicLineでの作曲も楽しんで頂いているようで嬉しいです♪
一時期は凄いペースで曲を作ってましたね!
コミュニティにぬんさんが溢れてました(笑)


アゴォー

笑い事じゃないぞおお!!

ぬんさんといい、さかきさんといい
musicLineのせいで勉強がピンチなんだから!!
なにか対策を考えるべきじゃないか?

う~ん

そうだ、
1時間で強制終了する機能を付けよう!




なんちゃって~~


そんなことしませーん



ん?どこ飛んでった?
まったく言うだけ言って飛ぶなんて
スーも大変だな


スー

すみません💦
作曲を極めたり、楽しんで頂けるのは嬉しいですが、勉強も同じぐらい頑張ってください(切実に)😭

musicLineで勉強ピンチとかまずいもんな

そ、そうだね。。
(あと知らない子と二人にしないで💦💦)


続いてSNSで募集した質問です!
おすすめのLINEスタンプはありますか?


ぬん

僕のおすすめスタンプは『ポンコツエスト』です
ポンコツエストとは、毎月youtube で配信される短編Webアニメで、魔物が主人公のシュール系ギャグアニメです。
個性豊かなキャラクターたちが登場し、おもしろいです!
ぜひ買ってみてください!✨


スー

ぽちぽちぽちっと、検索〜☆

ポンコツクエスト~魔王と派遣の魔物たち~ 公式サイト|VAP

なるほど〜!
デザインが可愛いですね!
YouTubeで見ましたが、めっちゃ面白いです🤣

ちなみに、こっちがスタンプね

ポンコツクエスト - LINE スタンプ | LINE STORE

これはみんなにも是非見てほしい。
こういうゆるふわ系?の世界観は大好きです!


アゴォー

わっはっは
確かにこれは面白いわー
キャラクターもいいね☆
(もぉーーーどこいってたの

せっかくだしどこか1話だけ紹介したいな
どこがいいかな?


ぬん

一番好きな回は、『第二十八章「捕獲」』です。
スタモン使いを名乗るこの「イマヅカ」というキャラクターが大好きなのでこの回を選びました!

www.youtube.com

他の回もめちゃくちゃおもしろいのでぜひ見てみてください!✨


スー

いや~良いですね😆
第五章「武装」も思わず笑ってしまいました!
なんかじわじわ来るな~♪



さてさてぬんさんの人柄が掴めてきたところで、作曲についても質問していきます!

まず、ぬんさんが作曲に興味を持ったきっかけはなんですか?

アゴォー

とその前に紹介します!
お友達のアイスでーす☆

えーここで紹介!?

アイス

どうもー
呼ばれて来たアイスだよ~
アイス食べてるからアイスね


アゴォーとは駄菓子友達でーす
そうそう駄菓子屋でよく会うよね


今日はアゴォーがどうしてもって言うから来たよ!
そこまで言ってないけどね

。。。



本当は面白そうだから来た~☆
ちょいちょいコメントする役するわ⤴︎


また変なのが増えたな


スー

間の悪い紹介ですみません😅
アイスもコメントしてくれるみたいです!


では気を取り直して、
ぬんさんが作曲に興味を持ったきっかけを教えてください✨


ぬん

昔から絵を描いたり、ゲームで何かを作ったりしていて、”自分だけの創作物“というものが自分の趣味の軸となっていました。
そしてふと自分も作曲をしてみたいと思うようになり、ひたすら作曲ができるアプリを探しました。本当にこのアプリに出会えて毎日が幸せです!


スー

musicLineを見つけてくれてありがとうございます!
アプリが創作活動を始めるきっかけに繋がれば嬉しいです♪

ゲームでも創作系が好きだったんですね〜
どうぶつの森かな?

マインクラフトじゃない?

シムシティって線もあるな

それで、ゲームでは何を作ってましたか?


ぬん

主に『とびだせどうぶつの森』と『マリオメーカー2』の2つですね!
これら以外にはなんのゲームにも手を出さないほど夢中でやり込みました〜


スー

やっぱりどうぶつの森ですよね♪
ああ、マリオメーカーね😃

どんな街やステージを作ったのか気になるな~
ぬんさんはかなりやり込むタイプですね!


次に、好きな楽器はなんですか?


ぬん

圧倒的に誰がなんと言おうとピアノです。
チェンバロが時を経て強弱をつけられるピアノという素晴らしい楽器に進化し、表現の幅が何百倍にも広がったことで、静かで落ち着いた雰囲気の曲から緊張、スピード感のある激しい曲までなんでも似合ってしまうという化け物級にすごい楽器です!!

取り乱しました
とりあえずみんなもピアノを崇めましょうね


スー

ピアノ愛が凄い😅

じゃあピアノはチェンバロの進化系ってことですね♪
確かにピアノは1人で幅広く表現できてすごいですよね〜!


アゴォー

ぺちゃぺちゃぺちゃちゃっと、検索☆

やっぱり、変な音してない?
ああ、、オレのアイスこぼしたんだった
。。

参照ページ チェンバロ - Wikipedia

これがピアノの祖先か!
なんか鍵盤が黒い?
このレトロ感と光の加減がいいね

光の加減はチェンバロとは関係ないけどな

スー

ピアノの歴史は勉強になりました!
どうやらピアノとチェンバロでは弦の振動させ方が違うみたいですね~
ピアノはハンマーで叩くのに対して、チェンバロは爪で弾いて音を出すらしい😮


続いて、今から始める作曲初心者の方にアドバイスをお願いします♪


ぬん

とにかく自分の好きな曲、作りたい曲の雰囲気、ジャンルを見つけてください!
それが自分のアイデンティティとなるはずです。
僕は自分のアイデンティティを見つけるためにいろんなジャンルの作曲に挑戦しましたが、
どのジャンルもそれぞれの良さがあって、優柔不断な僕は『これ!』といったものは決められずに今も新ジャンルに挑戦し続けています
もしかするとまだ自分の知らないジャンルにどハマりするかもしれません。
自分好みの雰囲気の曲を見つけるのはきっと作曲が上手くなる近道になるはずです!


スー

まずは自分がどんな雰囲気やジャンルが好きなのかを見つけるということですね!
作りたい方向性を知るためにも、色々と試していく攻めの姿勢は見習いたいものです✨


アゴォー

あと、ぬんさんと言えば連続殿堂入りが注目されるけど、 僕はスペクトラムアート(MIDIアート)の方も知ってほしいな~

ぬん「MLでアニメを作ってみた」

https://3musicline.com/community/165083 (アプリリンク)

曲はカービィの「グリーングリーンズ」のアレンジでもちろん曲も良いし
曲に合わせて出てくるカービィにはテンション上がったな!


スー

そうそう~♪
イデアが斬新で、目で見ても楽しいってのが良いですね!

目でも音を楽しむっていう
musicLineのコンセプトに合致したわけだ
へーそんなコンセプトあったんだ


とにかくソングビジュアのテーマ「スペクトラム」の仕組みをとてもよく研究されて、新しいものに挑戦するぬんさんの精神が感じられました😁


ではここで、今回インタビューするきっかけになったコンテスト投稿曲の「僕らの桃源郷」を紹介します♪
疾走感がありポップでおしゃれで素敵です✨
また、冒頭の文字が表示されるMIDIアートにも注目です!

ぬん「僕らの桃源郷

https://3musicline.com/community/179402 (アプリリンク)

この曲はどのような部分にこだわって制作しましたか?
「制作期間一カ月の本気モードで頑張った」ってコメントしてたね


ぬん

こだわったポイントとしては、自分の中に前提として音楽は『イントロから惹かれる曲』と『何度も聞くうちに惹かれていく曲』の二つに分かれると思っていて、コンテストでは圧倒的に最初が肝心なので、ピアノのみの続きが気になる出だし、何かが始まる予感のするイントロ、そしてMIDIアート。と使えるものは存分に使って曲の始まり方を工夫しました!
4分超えの曲は、飽き性の僕にはなかなか作れないので本気を出せたと思っています!


スー

確かにイントロからどんな曲が聴けるか楽しみになりますね!
それでも途中で雰囲気が変わったり、リズムにアクセントを入れたり最後までワクワクが続くようになっています。
飽き性には全然感じられませんが、長い曲ほど構成やバランス調整に根気が入りそうですね😳
その辺りの繊細な音作りは流石です〜


では最後にみなさんに聴いてもらいたい自分のオリジナル曲名を教えてください


ぬん

『輪廻と揺ぐ』(りんねとゆるぐ)です。
ランキング3位以上にすら入っていない曲ですが、個人的にとても自信がある曲です。ゆったりとした曲調に切なさを存分に注ぎ、大好きなピアノも活躍するのでまだ聞いたことない方は聞いてくれると超喜びます。

ぬん「輪廻と揺ぐ」

https://3musicline.com/community/173895 (アプリリンク)


スー

聴きました!
楽器の使い方もコードもメロディもおしゃれですね♪
ピアノの伴奏というか裏メロが効いています😆

ぬんさんありがとうございました!

次回は今回の企画ラストのがちゃさんにインタビューです。
9/7頃投稿予定ですので、お楽しみに〜

インタビュー インタビュー



挿絵のLINEスタンプ


mint秋さんインタビュー

mL民のインタビュー企画第3弾、2人目のインタビューです。
(インタビュー企画通算で11人目です!)
※mL民:作曲アプリmusicLineユーザーのこと
(「」タグで他の方の紹介も見れます☆)

インタビュー企画第3弾はmusicLine10周年記念の作曲コンテストで上位だった4名の方を紹介します。
2人目は、一般部門3位の mint秋さん です。

DMでのやり取りをインタビュー形式にまとめました。


スー

それではmint秋さん、よろしくお願いします。
まずユーザーネームの由来を聞いてもいいですか?


mint秋

できるだけ印象に残る名前にしようと思って、1単語とかのシンプルな名前ではなく、単語を2つ繋げた名前にしようとしました。
チョコミントと秋が好きなので、結局その2つを合わせてmint秋にした、というのが由来です。
だいぶ安直です笑


スー

そんな感じだったんですねー
名前の響きが良くて素敵ですよ!

それとチョコミント美味しいですよね〜😋


ダラーン

mint秋さんはアイコン背景のくすみミントがオシャレ
どことなく肌寒い秋っぽい空気を感じます♪


あと物悲しいミステリアスな女性が魅力的☆
もしかしてmint秋さんだったりして!?
アイコンについてなにか教えてください~


mint秋

美大に通っていた友人がいて、その友人に描いてもらいました!
「私のユーザーネームの由来であるチョコミントと秋の要素を取り入れてほしい」、とだけ伝えたらこんなにも素敵なイラストが返ってきたので、気に入って使っています!
アイコンの人物はミステリアスで素敵な女性ですが、もちろん私ではありません笑笑
いつかこんな素敵な方になりたいものです…


ダラーン

いいな~
最近絵に興味があるから是非習いたいです!
ずっと見ときたい素敵な雰囲気だなあ

スー

良い曲を作るmint秋さんはきっと素敵な方です😁


それでは、ひとこと自己紹介をお願いします。


mint秋

改めまして、mint秋と申します!
趣味はmusicLineでの作曲のほか、ポケモン、コスメも好きです!
よろしくお願いします!


スー

ポケモンね♪

スーもポケモンみたいだよ〜

。。。

。。。

💦💦


ダラーン

中でも好きなポケモンはいますか?


(もーなんかいってよー
(え、やだよ


mint秋

どのポケモンも魅力的なので、いつもいろいろ目移りしちゃいますが、最近の推しはコライドンというポケモンです。
見た目は大きくてゴツいドラゴンで、伝説のポケモンなのですが、
ゲームだと意外と怖がりだったりサンドイッチが大好きだったり人懐っこかったり、主人公を背中に乗せて一生懸命バタバタ走ってくれたり、なんか行動が犬みたいで可愛いです笑


ダラーン

どれどれ~

カタカタカタ、検索

参照ページ
コライドン | 『ポケットモンスター スカーレット・バイオレット』公式サイト

わお!確かにゴツゴツのカッコいいポケモンですね~
たくましいのに可愛い一面もあるのが惹かれるってことかあ♪

スー

ちょっと意外でした😲
もっとヤドンとかニョロモとか可愛い系が推しだと思ってました!


ダラーン

ん?
ちょっと世代が古いかもね☆

まあ今も昔もポケモンは魅力的ってことだね~


それからー
あと、コスメ。。。ね!
コスメコスメ

スーくんコスメだって〜


スー

あ、はい
コスメね〜

コスメコスメ

コスメ?

。。。



????

化粧品のことだな



ほら、好きなブランドとか今ハマっているメイクとか聞いてみ






スー&ダラーン

だれーーーーーー??

。。。



アゴォー

あーごめんごめん
邪魔したね



気にしないで





。。気にしないで


. . . . . . .



(気になるーーーーーー


スー

あ、では好きなブランドありますか?💦
どんなメイクにハマっているのかも教えてください!


mint秋

安くて可愛いプチプラが大好きなので、基本的にはプチプラのものを買ってしまいますが、
ちょっと高価格帯のものだと、コスメデコルテというブランドが好きです!可愛い色味が多くて、でもギラギラしすぎず上品なのが気に入ってます!

ハマってるのは、オレンジとか明るいピンクをメインにしたメイクです!
今は髪のインナーカラーが明るめなので、それに合わせたメイクをしてます!
今度美容院に行くときは暗髪にしようと思ってるので、そのときはラベンダーカラーとか使って透明感を意識したメイクをやりたいな〜と思っています。
そのときの髪色とか目指す雰囲気に合わせてメイクを変えるのが楽しいです


スー

ぽちぽちぽちポチポチポチポチっと

ふむふむ。


プチプラ

「プチプラ」とは「プチプライス」の略。「petit」というフランス語+「price」を組み合わせた言葉です。「petit」には「可愛い」というニュアンスが含まれるので、「プチプラ」とは「安くていいもの」という意味になります。
プチプラとは? | 美的.com より


コスメデコルテ

DECORTÉ(コスメデコルテ)

ラベンダーカラー

メイクにラベンダーカラーを取り入れるだけで、白く透明感のある肌に見える。
透明感のあるラベンダーメイクに注目 - @cosmeまとめより



なるほどー勉強になるな~
奥深いー😲
メイクも作曲と一緒で雰囲気に合わせて変えられたら楽しそうですね😊

mL民インタビューでそんな人初めてです♪ 笑
では気を取り直して、次の質問に行きましょう!

SNSで質問を頂いたのですが、作曲以外で最近ハマっていることはありますか?


mint秋

最近のマニアックなマイブームだと、自己分析が好きです笑
本を読んだり、過去のことを振り返りながら自分のことを少しずつ知っていくのがなんだか楽しくて笑
あと自分の気持ちを文章にして書き綴るのが好きで、別名義ではありますがブログを書いていたころもありましたね。今は更新していませんが…。
自己分析とか文章を書き綴る、といった趣味を通じて、自分とじっくり向き合うのが好きなのかもしれません。


スー

自己分析、、、それはマニアックですね😲

ブログって他の人がどんなことを思っているのかとか、どんな気持ちなのかを知れるので興味深いです!
そういう意味ではSNSもそうですね。
僕もたまにmL民皆さんのポストも見ては楽しんでます~♪

ちなみに自己分析結果はどんな自分でしたか?😄


mint秋

基本的に安定志向で、のんびり屋で平和主義、穏やかなタイプだけど、謎に頑固なところもあるようです笑


スー

かなり詳細に分析してますね。
謎に頑固なところがある(笑)
でも芸術家は頑固じゃないと良いものはできないですよ😋



さてさてmint秋さんの人物像がわかってきたところで、作曲について質問していきます!

まず、作曲に興味を持ったきっかけはなんですか?


mint秋

小学校では合唱部、中高では吹奏楽部に入っていて、元々音楽大好き人間でした。
ある日、自分の好きな音や思いついたフレーズを曲にすることで形にできたら楽しいだろうな、と思い立ったのが、作曲を始めたきっかけです!
作曲を始める前から、「こんなコード進行で、こんなメロディの曲があったらいいな〜」と、漠然と頭の中で曲を考えたりしていたことが多かったので、最初はそういった頭の中のメロディを打ち込んでみるところから始まりましたね。
初めて1曲作り上げられたときは本当に嬉しかったです。


スー

作曲を始める前からコードやメロディが思いついていたなんてすごいです!

そんなふうに作曲を始めたんですね~
でも頭の中にメロディーがあったら迷わず始めるべきですよ(笑)

好きな楽器はなんですか?


mint秋

mLだとよくファンタジアを使ってしまいますね。意外とどんな曲にも馴染みやすいし、ファンタジアを入れるだけで響きが強くなり美しくまとまる気がします。
あとはアコースティックピアノ、ハープ、チェレスタ、フルートもよく使います。
ヴァイオリンやホルンも、曲が煌びやかになって好きです!
曲に彩りを与えてくれるような華やかな音が好きなんだと思います。


スー

ファンタジアね〜♪
幻想的な音がしますよね

ファンタジアやシンセサイザーのカテゴリーは響きが強かったり癖が強いので、なかなか使いどころが難しいかも?🤔
でもイメージ通りの空間を作れるくらい使いこなせたら楽しそうですね✨

なんだか僕も曲に彩りを与えたくなってきました!
紹介して頂いた楽器を使ってみます~😊

作曲する際に心がけていることはありますか?


mint秋

これは完全に私の好みの話になるんですが、私自身切ない展開や切ないメロディーが好きなんです。
なので、どんなに明るい曲でも途中で切なさを感じるような展開やメロディを入れたり、少し影のある場面を差し込んだり。
そうすることで曲に深みが出るような気がするんです笑
そういう意味では、場面や雰囲気のメリハリは結構心掛けてるかもしれません。

スー

なるほど〜
確かに明るい曲でも少し影がある方が深みが出るような気がします!

ダラーン

そうか
少し影のある部分とか雰囲気のメリハリがmint秋さんの魅力になってるんだな

ところで切なさを感じるような展開やメロディってどうすればできるんだろう?


mint秋

一番わかりやすくてやりやすいのは、盛り上がってきたところで急にフッと音量とかテンションが下がるような展開にすることですかね。
それだけでもメリハリができるし、盛り上がってきたタイミングで急激にテンションが下がることでちょっと切ない雰囲気も演出できるので、私自身よくやってしまいます。


ダラーン

なるほどーー
まずは盛り上げることが大切なんですね!
テンションの落差が切なさに感じるってことですかあ~♪
やってみようっと

スー

そうそう。
あとさっきも言われてましたが、mint秋さんは切ないメロディーの印象が強いので、10thコンテストのとても爽やかな祝典音楽は衝撃を受けました〜

mint秋「musicLineのための祝典音楽(original)」

https://3musicline.com/community/179190 (アプリリンク)

とても晴々しく華やかで、祝福する気持ちが伝わりますね♪
切ないイメージとは真逆のように思えますが、祝典をイメージした曲は作曲していかがでしたか?


mint秋

かなり吹奏楽曲の影響を受けて作りました!吹奏楽コンクール課題曲のマーチのような爽やかさを意識しましたね。
全体的に明るい曲ですし、特に前半部分は祝福感マシマシで華やかなイメージを意識しましたが、途中で切ない雰囲気を差し込むことも忘れずに作ったんですよ〜。ラスサビ前とか、曲の終わりに差し掛かってきたあたりのピアノのパートとか。

難しかったのは、メロディを担当するパートの選定ですかね💦最終的には、ホルンにかなり頑張ってもらったのですが…。
展開が進むにつれて、メロディの楽器がいろいろ移り変わっていくような彩り豊かな曲にしたかったので、「この場面のメロディはどの楽器にやらせようかな…」といろいろ考えました。
トランペットとかストリングスとか、いろんな楽器を組み合わせたりもしましたね。


スー

ほんと華やかさ全開です!!
切ない雰囲気を挟むことがアクセントとなって、より華やかに聴こえるのかもしれないですね!

メロディの楽器が移り変わっていく展開を自然にするのは難しそうですね~
言われてみると、確かにホルンのメロディー頑張ってますね(笑)

続いて、作曲初心者の方にアドバイスはありますか?


mint秋

私がアドバイスするというのも大変恐縮ですが…。
まずは、自分好みの曲を作ることを目指すのが良いと思います!作曲を続けるコツはやはり楽しむことだと思うので、自分を喜ばせるつもりで、自分の好みを詰め込むところから始めてみてください。

作曲の良いところは、自分の好みを存分に詰め込んだ世界に一つだけの曲を生み出せることだと思っているので、万人受けする曲を目指すこともときには大事ですが、まずは自分の好みに刺さるような曲作りを目指すと楽しく続けられると思います!
自分の曲の一番のファンは自分自身、ってマインドでいられると良いですよね!

ダラーン

自分の曲の一番のファンは自分自身か~
身に染みるなー

とりあえず自身を楽しませるとこからか。。


mint秋

それでも、作曲が義務的になってしまって曲作りを楽しんでできないときは他のいろいろな人の曲を聴くようにしています。
作曲から離れる時間をとることで、時間はかかれどモチベーションが戻ってくる気がします。様々な曲に触れておくことで、作曲の引き出しも増えていることも多いというメリットもあります!


ダラーン

そっかー
楽しくないって感じたら距離を置くってことも良いね!
またしたくなったらすればいいし。
気楽に考えたらいいやー


スー

ありがとうございます!
とってもためになりました😊

では最後に、みなさんに聴いてもらいたい自分のオリジナル曲名を教えてください


mint秋

私自身、自然などの情景を音楽で表現するのが好きなので、そういった情景描写系の曲を2つ紹介したいと思います!

雨と薔薇(original)
雨の雫が薔薇の花に滴るような様子をモチーフに作曲した曲です。
殿堂入りしたとかではないですし、メロディ以外はかなりシンプルにまとめてる曲ですが、個人的に好きな要素をたくさん入れた曲なんです。やはり綺麗めで切ない曲が好きです笑

https://3musicline.com/community/112083 (アプリリンク)

イーグレット(original)
こちらは、鷲や鷹をモチーフに、雄大な自然や空の中での情景をイメージして作った曲です。
厳しい自然を舞台に、翼を広げて勇敢に力強く舞い上がる情景や、淡々と静かに獲物を狙いながら息を潜め飛んでいるような様子など、自分なりにいろいろイメージを膨らませて作曲しました。
聴いている皆さんにも自分なりの情景を思い浮かべ、想像しながら聴いていただけると嬉しいです!

https://3musicline.com/community/60520 (アプリリンク)


スー

雨と薔薇の荒ぶるメロディー最高ですね!
雫が滴る様子が思い浮かびます✨

ダラーン

イーグレットはとにかく力強い
雄大な自然に羽ばたいている感じがするー
ほんと情景描写の表現力は凄いな〜

あとこれも良いよ♪

mint秋「憂雨(original)」

https://3musicline.com/community/80516 (アプリリンク)

ウレイアメと読むんだよね〜
実は共有動画のテーマ「バブル」を作るときには、この曲に合わせてデザインを考えたんだー
長音が効いていたり、メリハリのある曲だと良い感じに波打つのでみんなも使ってみてね!


スー

ダラーンこのテーマ作るのこだわってたもんね〜
あんまり人気ないけど😏
でも思い出に残る曲だね☆

mint秋さんお忙しい中インタビューに丁寧に回答いただき、ありがとうございました!

次回は最近の勢いが凄すぎる、ぬん/𝑵𝑼𝑵さんにインタビューです。 8/24頃投稿予定ですので、お楽しみに〜


インタビュー インタビュー



挿絵のLINEスタンプ


さかきさんインタビュー

mL民のインタビュー企画第3弾、1人目のインタビューです。
(インタビュー企画通算で10人目です!)
※mL民:作曲アプリmusicLineユーザーのこと
(「」タグで他の方の紹介も見れます☆)

インタビュー企画第3弾はmusicLine10周年記念の作曲コンテストで上位だった4名の方を紹介します。
1人目は、ビギナー部門1位の さかきさん です。
DMでのやり取りをインタビュー形式にまとめました。


スー

それではさかきさん、よろしくお願いします。
まずユーザーネームの由来を聞いてもいいですか?


さかき

MLの名前を決めるとき、テクノさかきという駅名の語呂と響きが良かったのでテクノさかきになり、色々あってただのさかきになりました。


スー

へー駅名だったんですね!

ぽちぽちぽちっと

参照ページ テクノさかき駅 - Wikipedia

おーいいところ☆
カタカナとひらがなが混じるユニークな駅名ですね〜


アゴォー

あとこの子はどういう生物なの?(笑)


さかき

こいつは1分ぐらいで作った何者でもない存在です!
強いて言うならミミズかな?


スー

ミミズ!!🤣
何者でもない存在ってことですね〜♪

それにしても絶妙な愛着がありますね。。

ん、なんか持ってるぞ

ほんとだ☆


では、ひとこと自己紹介をお願いします。


さかき

趣味でギターしてる吹部です。最近は読書にハマってます!
今年は受験生なのであんまり曲投稿できません!


スー

吹奏楽部でありながらも、ギターもしてるんですね!

アゴォー

わかるわかる〜
吹くのもいいけど、弾くのも捨てがたいって感じだね😏

1つには決められないのはわかるけど🤗
さかきさんの好きな楽器が知りたいなー


さかき

フルートです!ジャズやボサノヴァ、和風まで様々な顔を見せてくれるところが好きです!
でも、いつもの作曲で使うとなると難しいんですよね…


アゴォー

.


..


...



それなあ=

スー

いやピンときてない😂

すみません。アゴォー楽器はそんなに知らないのに。。
インタビュー張り切ってるみたいです😅


吹奏楽以外でフルートのイメージがあまりつかめないですが、様々なジャンルで活躍しているんですね☆
フルートのジャズって良さそうですね!さかきさんのフルートを使った曲も聴いてみます♪

ちなみに、吹奏楽ではどのパートを担当されているんですか?
やっぱりフルートでしょうか?


さかき

自分が担当パートはフルートではなくチューバです!ベースと同じ縁の下の力持ちの楽器で、稀にあるメロディがとても勇ましくてかっこいいです!


スー

え〜そうなんですね!
大きな楽器でかっこいいですよね✨
稀にあるメロディは胸が高鳴りそう😆

チューバ担当なのにフルートが好きなんてすごく音域に差がありますね!♪

アゴォー

ぺちゃぺちゃぺちゃちゃっと
あれ、変な音してる?

参照ページ チューバ - Wikipedia

おーこれがチューバね☆
ピカピカ!管楽器って艶が魅力的だな〜


スー

おー検索ありがとう!
やっぱりでかいー持つの大変そうですね。


そして受験生!
そんな時に10thコンテスト参加して頂いてありがとうございます😆

musicLineは学生の方も多いので、受験中の方も結構いたかもしれないですねー
勉強の邪魔になってたらすみません😂


アゴォー

確かに。。

アプリ使ってほしいけど受験は頑張ってほしいな


じゃあわかった !!
息抜きに作曲ってことで〜

勉強→作曲→勉強→作曲→勉強→勉強→勉強→作曲→作曲→作曲→作曲くらいのサイクルにしよか〜

スー

うん?それだと後半に作曲が追い抜いてるね😅
ばれたか


勉強も頑張ってきていると思うので、受験でもいい結果を残したいですね〜
今年は色々とアップデートで気が散ると思いますが、勉強を忘れずに頑張ってください!

それと
読書にハマってるんですね〜
読書こそ息抜きかな♪
受験といってもペース配分が大切ですからね〜
最後まで勉強頑張れるように適度な息抜きは必要です!

最近読んで良かった本はありますか?


さかき

最近読んだ中で一番良かったのは「アルジャーノンに花束を」です!
本当に面白いです!本を開いたときの衝撃と読後の言葉にできないあの気持ちを皆さんにも味わってほしいです!!!今すぐ買おう!!!!!!!!!!!!!!


スー

え〜!気になる!

ぽちぽちぽちっと

参照ページ アルジャーノンに花束を - Wikipedia

調べてみるとドラマ化とかもしていて、SF小説に新たな可能性を見出した一作みたいですね〜
SFなので宇宙とか未来社会を舞台にしていると思いきや、日常の一部分に限定したSFが絶賛されているようです!
これは面白そう😳早速読んでみます!


話は変わりますが、
さかきさんは作曲していて辛かったことはありますか?


さかき

辛いことばっかですね。曲が伸びないことと、音感が無さすぎることと、メロディセンスがないことと…作曲は辛いことだらけです!
だからこそ曲が伸びたり、自分の中で満足いくものができたときの喜びは凄まじいですね…!


スー

辛いことばっかですかあ…
確かに辛さがいっぱいある分、満足いく曲が作れたら嬉しいですね♪

自分の中で満足のいく曲はどのようなものがありますか?


さかき

コンテストで一位を獲得した「じゃあ、またね」ですかね。
今まではあまり自分の曲を好きになれなかったのですが、初めて本当に好きになれた自分の曲です。


スー

おめでとうございます!
本当に好きになれる曲を作れて良かったです!✨

さかき「じゃあ、またね」

https://3musicline.com/community/179619 (アプリリンク)


ちなみに、どんな記念日を思い描いて曲を作りましたか?


さかき

この曲を作る前の年度末、自分の顧問の先生が他の学校へ行く事になってしまったんです。
それに影響を受け、別れと出会いという2つの思い出が、いつか記念日となることをイメージして作りました!


スー

やばい。。
それ聞いてもっかい曲聴いたら感動しちゃった



顧問の先生も最後まで教え子を見届けられなくて辛かったと思います。でも時間が経つについれて、いい思い出になっていくでしょう😊
そういう実体験でその時に感じるものがあれば、追体験できる気持ちの籠った曲が出来上がりますね!


あと初めて使うテクニックがもりもりとコメントされてましたが、どのようなテクニックですか?


さかき

サビ前でテンポを半分にしたり、ボイシングを意識してみたり、今までやってこなかったことを取り入れました。
曲が1分なので実はテクニックそんなにもりもりでもないかも…


スー

いえいえーもりもりですよ☆

なるほど〜サビ前でテンポを変えることで印象的なサビになってるのかもしれないですね!
やってなかったテクニックに挑戦することで表現力も高まりますね♪


今後の目標はありますか?


さかき

目標は殿堂入りすることです!
将来的にはボカロpになりたいなとも思ったり…


スー

そういえば、まだ殿堂入りされてなかったんですね!なんだか、勝手に殿堂入りしていると思っていました♪
頑張ってください!

やっぱり作曲に慣れてくるとボカロPもしてみたくなりますか〜

尊敬してるボカロPさんはいますか?


さかき

尊敬しているボカロpは4人います!
いよわさん、ハチさん、るりあさん、原口沙輔さんです。
長くなりすぎるのでるりあさんと原口さんの2人に絞って紹介します。

原口沙輔さんは超前衛的な編曲ながらも曲がとても魅力的なところを尊敬しています!
るりあさんは昔ながらのボカロって感じのサウンドなのがすごい好きで、そういう曲を自分も作れるようになりたいです!

二人とも、ボカロpになってからの伸びがとんでもなく速いこともすごいと思っています!


スー

なるほど〜!

るりあさんは前回mL民としてインタビューさせて頂きましたね♪

現在はボカロPとしてご活躍されてます!😄

チャンネル Ruliea - YouTube

原口沙輔さんは前衛的な編曲が特徴的なんですね〜

チャンネル 原口沙輔 - YouTube

人マニアのボカロPでしたかーこれは聴いたことあります。
前衛的のさじ加減が難しそうですが、絶妙に癖になって良いですね♪


続いて、SNSで募集した質問です。
いつもどのくらいの時間に寝ていますか?


さかき

普段は7時間ぐらい寝てます!
でも長期休みになると10時間ぐらい寝てますね…


スー

睡眠時間が気になるのは少しわかりますね🤔
睡眠を削れば時間は確保できるんだけど、睡眠が少ないと頭が働かないし〜

さかきさんは結構寝てますね☆
でも受験生だと勉強で頭をフル回転ですし、よく寝て頭を休めることで効率の良さに繋がると思います♪


アゴォー

ちなみにダラーンは帽子がないと寝れないらしいよ


スー

あらまあ



それでは最後にみなさんに聴いてもらいたい自分のオリジナル曲名を教えてください!!


さかき

さかき「【100人記念】夏色デイズ」

https://3musicline.com/community/192599 (アプリリンク)


スー

最初のスチームドラムが効いてて、夏色感が出てますね〜あとメロディーもキャッチーで歌詞が聴きたくなっちゃいます😁
100人記念にふさわしい、夏っぽい爽やかな曲です!

これからの活動も応援しています。プレミアム機能も使ってくださいね!
でもまずは受験ですね😉
受験勉強もある中、ありがとうございました!

次回は運営も昔から気になっている、mint秋さんにインタビューです。 8/10頃投稿予定ですので、お楽しみに〜


インタビュー第二弾へ インタビュー



挿絵のLINEスタンプ


【iOS】作曲画面の進捗報告 7

musicLine(iOS)についての進捗。
MIDIプレイヤーで曲を再生する部分について報告します。

曲再生とテスト音の動作


実装状況
カテゴリタイトル補足
View
Composition
UI配置
ガイド表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
Community
UI配置
Composition
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Commnity
Common
コミュニティ
共通
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持


曲の再生やピアノ音を鳴らす処理について大まかな実装は完了しました。またコミュニティの実装にも着手しました。


全進捗マップを表示

カテゴリタイトル補足
View
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ツールガイド(ペン)長さ編集しているリズム音符、伸ばした時の削る範囲音符移動時、移動先の音階をわかりやすくする
ツールガイド(指)移動中の音符影、矩形選択の枠
ツールガイド(消しゴム)削除範囲、和音のみの削除範囲
ツールガイド(フレーズ)フレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
Community
UI配置
Dialog
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定 リピートフレーズは未実装
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Commnity
Common
コミュニティ
共通
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
Domain
データ構造
Json形式
Melody MelodyTrack, *MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, *DrumPhrase, BeatContainer, Beat
通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理


実装の詳細

MIDIのデータ構造

MIDIを再生するためのモデルを作りました。

MIDIのデータ構造

MidiControllerで曲の読み込みや再生を管理します。
再生する際は、まず再生する曲MidiSongchangeSong()メソッドで指定してMidiStreamを作成します。MidiStreamは曲情報や再生状況を保持してます。続いてplay()メソッドによりMidiPlayerMidiStreamを渡すことで再生します。
なお、MIDIファイルから再生したい場合はMidiReaderを使ってファイルをMidiSongモデルに読み込みます。


なぜCompositionとMIDIにモジュールを分ける? 理由は可読性を高めるためです。
実装したコードを後から見直しても分かりやすくするためです。

例えば、musicLineではSongモデルといっても、作曲中やコミュニティ閲覧中なのか、再生するための曲なのかと状況によって曲の概念(曲に付属する情報)が変わります。
もちろんモジュールを一緒にして曲の情報を片っ端から付けまくることはできますが、ある状況では不必要な情報が付いている状態となり可読性が低下します。

つまり状況を混ぜるほど複雑になり、どのメソッド・プロパティを使えばいいかわからなくなる危険性があります。
特に後々の機能拡張や不具合修正を考えると、コードはシンプルな状態にして可読性を高く保つことで効率的な開発ができますね。

この辺りの話に興味がある方はこちらの記事がおすすめ♪
little-hands.hatenablog.com


データ構造の変換(Composition → MIDI)

作曲モデルからMIDIモデルのデータ構造に変換できるように変換モデルSongConverterを作りました。
MIDI再生をするときは、MIDIモデルへ変換して再生します。

作曲とMIDIのデータ構造

SongConverterで作曲モデル(Song Track Phrase Element)をMIDIモデル(MidiSong MidiTrack MidiEvent)に変換します。
モデルを変換してしまえば、あとはMidiControllerMidiSongを渡すだけで再生できるので、わかりやすいですね。
このように事前に扱いやすいモデルに変換すると、モジュール間のアクセスを少なくなる(疎結合)のが良いです。


曲の再生
UI:再生バーと再生ボタン

再生ボタンをタップすると、画面の左位置の時間から曲が再生されます。なお、再生中は再生バーが表示されます。

曲の再生


曲を再生する処理の流れ

曲を編集して再生する流れ

1.曲の編集はCompositionモジュール内で完結しますが、2.曲の再生MIDIモジュールに再生を委託する必要があります。
曲を再生する場合には、MidiControllerMidiSongを渡す必要があります。しかし編集はSongを使っているので、そこまで編集した曲SongMidiSongに変換して渡します。MidiControllerは受け取ったMidiSongからMidiStreamを作成して再生を管理します。MidiStreamと一緒にMidiPlayerに問い合わせることで再生位置を取得します。


テスト音の再生
UI:テスト音のガイド

音で音階を確認できるように音符の作成や移動の時にテスト音を鳴らします。その際に、ピアノとピアノロールで鳴っている音階を光らせます。
あとは音階名も表示させたいですね。

またiOSでは動かす音符が和音の場合、和音で鳴るようになっています。Androidでは短音でしか鳴らないので、和音の鳴り方がいまいちわからないなと思ってました。

テスト音の再生

ちなみに指ツールで複数音符を同時に動かすときは、スワイプで掴んでいる音符の音が鳴ります。


曲の再生(最初から / 位置指定)

再生ボタン長押しで最初から再生します。
(この時に画面も最初に戻したいですが、まだ未実装です。)

また、スクロールバーをダブルタップでその位置から再生します。(iOS独自)
意外と便利そうなのでこの機能を付けてみましたが、誤動作が気になるところですね。

曲の再生(最初から / 位置指定)


再生速度の変更
UI:再生速度の表示

再生中に再生ボタンを右にドラッグすると再生速度が早くなります。
こちらもiOS独自の機能ですが、あまり利用用途がないかも?

再生速度の変更

再生速度の変更は必要ですかあ?
ちなみに左にドラッグすると0.5倍速になります。。。
使う時ないよね〜 (´ㅂ`; )

できそうなのでこの機能を付けてみましたが、こちらも誤動作が気になるところです。
あまり使わなそうだと思ったらリリース前に削除するかもしれないです。(;'-' )


再生処理の最適化
UI:再生ボタン(再生が遅い時)

音符が多くて再生準備に時間がかかる時は再生ボタンにインジケーター(くるくるアイコン)を表示するようにしました。
ちょっとしたことですが、タップできたかどうかがわかりやすいですね。

再生処理の最適化

また、再生後に編集してなければ前回のキャッシュを使うので、2回目以降はすぐに再生できます。



おわりに

MIDIプレイヤーで曲やテスト音を再生する部分について実装しました。
音が出せてようやく作曲アプリ感が出てきましたね✨

次は、使用している楽器で音を変えたり、楽器選択ダイアログあたりについて実装していきたいと思います!



描画表現の追求(OpenGL FBO)

今回は描画ライブラリOpenGLの表現を高める話。
OpenGLの機能FBOを用いることでフィルタを掛けます。

フィルタ表現



はじめに

musicLineでは、コミュニティでユーザーが投稿した曲を再生できるようになっており、再生している曲のイメージを可視化できるソングビジュアライゼーションという機能があります。

ソングビジュアライゼーション

そのソングビジュア機能ですが、ランキング等で上位に入った曲はキラキラのエフェクトを追加し、よりリッチな表現にしています。

キラキラエフェクト

リッチな表現

ちなみに、この辺りの話はこちらの記事で紹介しています。

その中で、殿堂入りした曲はキラキラエフェクトを加えた後、さらにカラフルフィルタを掛けてよりリッチな表現を追求しています。

キラキラエフェクトとカラフルフィルタ

よりリッチな表現へ



フィルタを掛けてレンダリング

フィルタはシーン(音符)の描画結果にさらに色を重ねるような表現です。 なので、フィルタは2回描画することで実現できます。

  1. シーンの描画
  2. 1の結果を使って描画


ちなみに、1回目の描画は画面に映し出されないのでオフスクリーンレンダリングと言います。1回目は画面ではなくテクスチャに描画し、そのシーンを描画したテクスチャにフィルタを掛けて画面に描画します。
なので、リアルタイムにテクスチャを作成しているとも言えます。

https://ics.media/entry/17120/images/180202_webgl2_mrt_offscreen_rendering__960.png
引用:サンプルで理解するWebGL 2.0 – Multiple Render Targetsによる動的なライティング表現 - ICS MEDIA



実装

AndroidOpenGLのFBOを使用して、画面にカラーフィルタを掛けてみます。

FBO実装の参考ページ
orangesignal.hatenadiary.org

処理の流れは

  1. 3種類(テクスチャ、FBO、レンダーバッファ)のバッファ領域確保
  2. 3種類のバッファの設定
  3. テクスチャへ描画 (1回目描画)
  4. フィルタを掛けて画面へ描画 (2回目描画)

となります。


1. 3種類(テクスチャ、FBO、レンダーバッファ)のバッファ領域確保

// テクスチャ
textureId = IntArray(1).also {
    GLES20.glGenTextures(1, it, 0)
}.first()

// FBO
fboId = IntArray(1).also {
    GLES20.glGenFramebuffers(1, it, 0)
}.first()

// レンダーバッファ
renderId = IntArray(1).also {
    GLES20.glGenRenderbuffers(1, it, 0)
}.first()

まずOpen GLのバッファを使うことを宣言します。


ちなみに、使用後必要がなくなったバッファは解放しないとメモリリークになります。

GLES20.glDeleteTextures(1, arrayListOf(textureId).toIntArray(), 0)
GLES20.glDeleteFramebuffers(1, arrayListOf(fboId).toIntArray(), 0)
GLES20.glDeleteRenderbuffers(1, arrayListOf(renderId).toIntArray(), 0)


2. 3種類のバッファの設定

// FBOをバインド
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId)

// レンダーバッファの幅と高さを指定します。
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width, height)

// フレームバッファのアタッチメントとしてレンダーバッファをアタッチします。
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renderId)

// テクスチャの設定
GLES20.glActiveTexture(textureSlot)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, texFormat, width, height, 0, texFormat, GLES20.GL_UNSIGNED_BYTE, null)

// FBOにテクスチャをアタッチ
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0)


// FBO, Textureのバインドを解除
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)

まず設定するFBOをバインドして、FBOに紐付けるレンダーバッファの設定をしています。
また、テクスチャも設定します。


3. テクスチャへ描画 (1回目描画)

// 使用するFBOの指定
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId)

// 使用するテクスチャの指定
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0)

// シーンの描画 (オフスクリーンレンダリング)
drawFunction()

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)

使用するFBOとテクスチャを指定してから、シーンを描画することでテクスチャに描画します。 drawFunction()の箇所で通常行っている描画処理を行います。


4. フィルタを掛けて画面へ描画 (2回目描画)

// 情報を送信
val propertyCount = 2 // X, Y 座標

// テクスチャ頂点とUV座標
val texVtPoss = listOf(
    Point(-1f, 1f),  // 左上
    Point(1f, 1f),  // 右上
    Point(1f, -1f), // 右下
    Point(-1f, -1f),// 左下
)
val vertexBuffer = toFloatBuffer(texVtPoss)

val texUvPoss = listOf(
    Point(0f, 1f),  // 左上
    Point(1f, 1f),  // 右上
    Point(1f, 0f),  // 右下
    Point(0f, 0f)   // 左下
)
val uvBuffer = toFloatBuffer(texUvPoss)

        
// GLSL設定
GLES20.glUseProgram(shaderProgramId)

// 機能有効
GLES20.glEnable(GLES20.GL_BLEND)
GLES20.glEnable(GLES20.GL_TEXTURE)
GLES20.glDisable(GLES20.GL_DEPTH_TEST)

// 機能設定
GLES20.glActiveTexture(textureSlot)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)

// 変数有効
GLES20.glEnableVertexAttribArray(texVtPosLoc)
GLES20.glEnableVertexAttribArray(texUvPosLoc)

// 変数設定
// stride 格納されているデータの間隔を(Objectサイズ)で指定する. 0 を指定したときは, データは密に並んでいるとみなされてsize*typeで自動的に計算される
GLES20.glVertexAttribPointer(texVtPosLoc, propertyCount, GLES20.GL_FLOAT, false, 0, vertexBuffer)
GLES20.glVertexAttribPointer(texUvPosLoc, propertyCount, GLES20.GL_FLOAT, false, 0, uvBuffer)
GLES20.glUniform1i(useTextureSlotLoc, 2) // GL_TEXTURE2
GLES20.glUniform1f(timeLoc, time * 0.001f)


// 描画
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, texVtPoss.size)


// 変数解除
GLES20.glDisableVertexAttribArray(texVtPosLoc)
GLES20.glDisableVertexAttribArray(texUvPosLoc)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)

// 機能解除
GLES20.glDisable(GLES20.GL_TEXTURE)
GLES20.glDisable(GLES20.GL_BLEND)

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId) で1回目の描画で作成したテクスチャを指定しています。
リアルタイムに作成したテクスチャを使って新しくレンダリングします。
今回の例では画面全体がカラフルになるようなShaderを書いています。

// uniform
val useTexSlotUni = "tex_id"
val timeUni = "u_time"

// attribute
val vtPosAttr = "v_pos"
val uvPosAttr = "v_uv"

// varying
private val uvPosVary = "f_uv"

override val vertexCode = """
    attribute vec2 $vtPosAttr;
    attribute vec2 $uvPosAttr;
    varying vec2 $uvPosVary;
    void main() {
        gl_Position = vec4($vtPosAttr, 0.0, 1.0);
        $uvPosVary = $uvPosAttr;
    }
""".trimIndent()

override val fragmentCode = """
    precision mediump float;
    varying vec2 $uvPosVary;
    uniform sampler2D $useTexSlotUni;
    uniform float $timeUni;
    #define PI 3.14159265359
    
    void main() {
        vec4 color = texture2D($useTexSlotUni, $uvPosVary);
        vec3 shift = vec3(100.0 * (pos - $timeUni), 1.0, 1.0);

        gl_FragColor = vec4(shift_col(color.rgb, shift), color.a);
    }
""".trimIndent()



全コードを表示

class ColorfulShiftShader() {

    // region Property
    private val textureSlot = GLES20.GL_TEXTURE2 // テクスチャ使用用にGL_TEXTURE1は開けとく
    private val textureId: Int
    private val fboId: Int
    private val renderId: Int
    override val program = Program()

    // Location
    private val texVtPosLoc: Int // 頂点位置
    private val texUvPosLoc: Int  // UV位置
    private val useTextureSlotLoc: Int  // テクスチャスロットNo
    private val timeLoc: Int  //時間

    // endregion

    // region Initializer
    init {
        loadProgram()

        // Textureを作成
        textureId = IntArray(1).also {
            GLES20.glGenTextures(1, it, 0)
        }.first()

        // FBO のバッファ領域確保
        fboId = IntArray(1).also {
            GLES20.glGenFramebuffers(1, it, 0)
        }.first()

        // レンダーバッファ領域確保
        renderId = IntArray(1).also {
            GLES20.glGenRenderbuffers(1, it, 0)
        }.first()

        setupFBO(textureSlot, textureId, fboId, renderId, GLES20.GL_RGB)

        // Location設定
        texVtPosLoc = GLES20.glGetAttribLocation(shaderProgramId, program.vtPosAttr)
        texUvPosLoc = GLES20.glGetAttribLocation(shaderProgramId, program.uvPosAttr)
        useTextureSlotLoc = GLES20.glGetUniformLocation(shaderProgramId, program.useTexSlotUni)
        timeLoc = GLES20.glGetUniformLocation(shaderProgramId, program.timeUni)
    }

    private fun setupFBO(textureSlot: Int, textureId: Int, fboId: Int, renderId: Int, texFormat: Int = GLES20.GL_RGBA) {

        // FBOをバインド
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId)

        // レンダーバッファの幅と高さを指定します。
        GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width, height)

        // フレームバッファのアタッチメントとしてレンダーバッファをアタッチします。
        GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renderId)

        // テクスチャの設定
        GLES20.glActiveTexture(textureSlot)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, texFormat, width, height, 0, texFormat, GLES20.GL_UNSIGNED_BYTE, null)

        // FBOにテクスチャをアタッチ
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0)


        // FBO, Textureのバインドを解除
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)
    }

    // endregion

    // region Method
    fun draw(drawFunction: () -> Unit) {

        drawInFBO(drawFunction)

        // 情報を送信
        val propertyCount = 2 // X, Y 座標

        // テクスチャ頂点座標
        val texVtPoss = listOf(
            Point(-1f, 1f),  // 左上
            Point(1f, 1f),  // 右上
            Point(1f, -1f), // 右下
            Point(-1f, -1f),// 左下
        )
        val vertexBuffer = toFloatBuffer(texVtPoss)

        // テクスチャUV座標
        val texUvPoss = listOf(// テクスチャのUV座標
            Point(0f, 1f),  // 左上
            Point(1f, 1f),  // 右上
            Point(1f, 0f),  // 右下
            Point(0f, 0f)   // 左下
        )
        val uvBuffer = toFloatBuffer(texUvPoss)

        // GLSL設定
        GLES20.glUseProgram(shaderProgramId)

        // 機能有効
        GLES20.glEnable(GLES20.GL_BLEND)
        GLES20.glEnable(GLES20.GL_TEXTURE)
        GLES20.glDisable(GLES20.GL_DEPTH_TEST)

        // 機能設定
        GLES20.glActiveTexture(textureSlot)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)

        // 変数有効
        GLES20.glEnableVertexAttribArray(texVtPosLoc)
        GLES20.glEnableVertexAttribArray(texUvPosLoc)

        // 変数設定
        // Ref:stride 格納されているデータの間隔を(Objectサイズ)で指定する. 0 を指定したときは, データは密に並んでいるとみなされてsize*typeで自動的に計算される
        GLES20.glVertexAttribPointer(texVtPosLoc, propertyCount, GLES20.GL_FLOAT, false, 0, vertexBuffer)
        GLES20.glVertexAttribPointer(texUvPosLoc, propertyCount, GLES20.GL_FLOAT, false, 0, uvBuffer)
        GLES20.glUniform1i(useTextureSlotLoc, 2) // GL_TEXTURE2
        GLES20.glUniform1f(timeLoc, time * 0.001f)

        // 描画
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, texVtPoss.size)

        // 変数解除
        GLES20.glDisableVertexAttribArray(texVtPosLoc)
        GLES20.glDisableVertexAttribArray(texUvPosLoc)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)

        // 機能解除
        GLES20.glDisable(GLES20.GL_TEXTURE)
        GLES20.glDisable(GLES20.GL_BLEND)
    }

    // オフスクリーンレンダリング(テクスチャへ描画)
    private fun drawInFBO(drawFunction: () -> Unit) {

        // 機能設定
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId)
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0)

        drawFunction()

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)
    }
    // endregion

    // region InnerClass
    class Program : Shader.Program() {

        // uniform
        val useTexSlotUni = "tex_id"
        val timeUni = "u_time"

        // attribute
        val vtPosAttr = "v_pos"
        val uvPosAttr = "v_uv"

        // varying
        private val uvPosVary = "f_uv"

        override val vertexCode = """
            attribute vec2 $vtPosAttr;
            attribute vec2 $uvPosAttr;
            varying vec2 $uvPosVary;
            void main() {
                gl_Position = vec4($vtPosAttr, 0.0, 1.0);
                $uvPosVary = $uvPosAttr;
            }
        """.trimIndent()

        override val fragmentCode = """
            precision mediump float;
            varying vec2 $uvPosVary;
            uniform sampler2D $useTexSlotUni;
            uniform float $timeUni;
            #define PI 3.14159265359
            
            void main() {
                vec4 color = texture2D($useTexSlotUni, $uvPosVary);
                vec3 shift = vec3(100.0 * (pos - $timeUni), 1.0, 1.0);

                gl_FragColor = vec4(shift_col(color.rgb, shift), color.a);
            }
        """.trimIndent()
    }
    // endregion
}



おわりに

今回はOpenGLの機能FBOを用いてフィルタを掛けてみました。
もっとリッチな表現を目指したい気持ちもありますが、作曲の機能拡張やiOS版の開発があるので深追いはやめておきます。。(・ω・;)