AudioProcessorValueTreeStateを使ったパラメータ管理 独自リスナー実装編

AudioProcessorValueTreeStateを使ってパラメータ管理が楽になった!最高!てな感じなんですが、パラメータの変更に連動して別の処理を呼びたい/値を変更したい場合があると思います。AudioProcessor::setParameterだとProcessor側のパラメータに値を設定するついでに好きな処理を書いておけば済む話ですが、AudioProcessorValueTreeStateでは?

AudioProcessorValueTreeStateは独自にリスナーを追加できるので実装します。

まずリスナーを定義。
AudioProcessorValueTreeState::Listenerを継承してparameterChangeをオーバーライドします。

// Processorの処理や値にアクセスするという想定でインナークラスを定義
class TestAudioProcessor  : public AudioProcessor
{
/* 中略 */
private:
    struct TestParameterListener : AudioProcessorValueTreeState::Listener
    {
    public:
        TestParameterListener(TestAudioProcessor& p);
        void parameterChanged(const String& parameterID, float newValue) override;
    private:
        TestAudioProcessor& _p;
    }
/* 中略 */
}

実装

// コンストラクタでアウタークラスのインスタンスをもらう
TestAudioProcessor::TestParameterListener::TestParameterListener(TestAudioProcessor & p)
    :_p(p)
{
}

// testMethodの呼び出し
void TestAudioProcessor::TestParameterListener::parameterChanged(const String & parameterID, float newValue)
{
    _p.testMethod(newValue);
}

Processorのコンストラクタとかで)AudioProcessorValueTreeStateのインスタンスにリスナーを追加します。

parameters.addParameterListener("test", new TestParameterListener(*this));

これでtestパラメータに連動して独自に定義したTestParameterListenerが呼び出されます。
やったね。

AudioProcessorValueTreeStateを使ったパラメータ管理

AudioProcessorValueTreeStateについて

JUCEでパラメータ管理を簡単に行うためのクラス。(多くの場合において)従来のAudioProcessorを用いた方法やAudioProcessorParameterを用いた方法よりコードが短く、分かりやすくなる。

公式のチュートリアルを読めば使い方は大体分かると思うので、個人的に補足したいところだけを好き勝手に書く。Tutorial: The AudioProcessorValueTreeState class | JUCE

従来の方法

AudioProcessorを用いた方法

手順としては大まかに以下のようになる。

  • AudioProcessorでパラメータ用の変数を定義
  • AudioProcessorでParameter系の関数を実装
  • PluginEditorでGUIコンポーネントを定義
  • GUIコンポーネントのイベント処理を実装
  • タイマー処理を実装
  • パラメータの保存/読込処理を実装

実装量が多く、AudioProcessorとPluginEditorでパラメータを二重管理するような形になる。ホストを介したPluginEditor→AudioProcessorのパラメータ変更通知も(必要があれば)自前で正規化しないといけない。そして、公式にてAudioProcessorのParameter系の関数は廃止予定とアナウンスあり。

AudioProcessorParameterを用いた方法

廃止される上記方法に取って代わる方法で、大分スマートになった。今回紹介するAudioProcessorValueTreeStateはAudioProcessorParameterのラッパーなので、用途に合わなければAudioProcessorParameterを継承したクラス(AudioParameterFloat等)を使って作り込むことになると思う。

AudioProcessorValueTreeStateを用いた方法

AudioProcessorでAudioProcessorValueTreeState::createAndAddParameterを呼び出してパラメータを追加する。あとはPluginEditorでGUIコンポーネントと先ほど追加したパラメータを連携させれば完了。連携したGUIコンポーネントはパラメータの範囲や初期値が設定されるので別途設定する必要はない。パラメータの保存/読込も一括で処理可能。

チュートリアルの補足

normalisableRange

createAndAddParameterの第4引数。値のレンジ(最小値・最大値・刻み幅)を指定する。[0,1]の範囲以外を設定しても問題なく、(必要がある箇所では)勝手に正規化される。

valueToTextFunction

createAndAddParameterの第6引数。(Cubaseで言う所の)一般エディタへ値をどう表示するかを設定できる。nullptrを渡した場合、[0,1]に正規化されて表示される。渡ってくるvalueは正規化されていない値なので、基本的にはreturn String(value);しておけば問題ないはず。

textToValueFunction

createAndAddParameterの第7引数。valueToTextFunctionの逆で数値がキーボードから入力された時に呼ばれるものだと思うんだけど、よく分からない。ブレークポイントを張ってデバッガをかけても止まらない。ちなみにキーボードからパラメータを入力しようとすると正規化されてしまって、入力した値がそのまま設定されないので非常に困る。だれか詳しい人教えて下さい。

Neko Guitars Claymoreのハードウェアを交換した

7弦ギターのペグ、ブリッジ、ノブを交換しました。

Neko Guitarsとは

海外の新興ギターメーカーです。
ヘッドレスとかブラックマシーンぽいやつとか、時流に乗った製品が多いです。
主にFacebook上で活動していますが、日本向けのTwitterもあります。
https://www.facebook.com/NekoGuitars/
twitter.com


日本市場へのサポートが手厚かったため、海外新興メーカーとしては珍しく国内に購入者が多いです。
Twitterで検索すれば多くの情報を手に入れることができます。

はい。

交換前

f:id:delatetei:20170527192355j:plain
f:id:delatetei:20170527193910j:plain
自分のClaymoreは1st Runモデルです。
ピックアップは白い韓国製のものでしたが、国産の千石ピックアップに交換済み。
ペグ、ブリッジは謎。精度はあまり良くないです。
2nd RunからはHipshotが標準搭載されています。

パーツについて

Hipshotがポン付けできます。

HipshotのGrip-LockはClosedタイプを選びます。
一般的にGrip-LockといえばOpenタイプだと思うので、気をつけたほうが良いです。
Openタイプはネジ位置が違うのでポン付けできません。
f:id:delatetei:20170527194724j:plain

交換する

黒色もつまらないのでゴールドパーツにしました。
Jacksonが好きな感性。。。
ただClaymoreはつや消し(サテンブラック)なので色味が合うか不安。

交換自体はポン付けなので困難はないです。
Hipshotのペグの方がネジが二回り大きいので、ネジ穴を適当にさらいます。
f:id:delatetei:20170527195118j:plain

交換後

f:id:delatetei:20170527195525j:plain
f:id:delatetei:20170527195529j:plain
まぁこんなもんですかねー。
Hipshotのゴールドは色味がかなり黄色いので、くすんでくると馴染むかな?


f:id:delatetei:20170527195532j:plain
おわり。

XEMのティッカーを投稿するTwitter BOTを作った

仮想通貨のNEM/XEMのティッカーを投稿するTwitter BOTを作りました。
ZaifからXEMのティッカー(終値、高値、安値、VWAP、出来高、売値、買値)を取得して10分毎に呟きます。

twitter.com
f:id:delatetei:20170423173747p:plain

NEM/XEMは急成長している仮想通貨です。
世間的な知名度はまだまだで、レートを見るにもわざわざ取引所にアクセスしないといけなかったりします。
そういうのが面倒くさかったので作りました。

完全に自分のために作ったものですが、フォロワー数も伸びてきているし、好意的な反応も頂けてよかったです。


技術的に語る所はまったくないです。
Zaifが公開しているJSONをパースして要素を取り出して投稿しているだけです。
技術的な困難さとコンテンツが有益かどうかは紐付かないと頭で分かっていても、こういうものを表に出すときは周りからどう思われているか分からなくて怖い。
でも、簡単なBotだったとしても、ネットに流れる情報が増えれば界隈も盛り上がるし、それで価格が上がれば良いかなという気持ちでリリースします。

ということで、よかったら見てやって下さい。

JUCE Frameworkを使ってディレイを作ってみた

手軽にVSTが作れるJUCE Frameworkを使ってディレイを作ってみました。
JUCE JAPANという入門書(良書!)を読んで始めたばかりなので、解説というか製作記のノリで書きます。

ソース

JUCEは手探り&C++は自信無い感じなのでソースを抜粋して載せます。

PluginProcessor.h

class DelayAudioProcessor  : public AudioProcessor
{
// 中略
private:
    int sampleNumPerDelayTime;
    int repeatNum;
    float delayTimeMiliSec;
    std::vector<boost::circular_buffer<float>> delayLine;
};

パラメータとしてメンバに以下を設定。

  • 1回ディレイするのに必要なサンプル数(sampleNumPerDelayTime)
  • 何回繰り返すか(repeatNum)
  • 何ミリ秒ディレイするか(delayTimeMiliSec)
  • ディレイ用のバッファ(delayLine)

ディレイは簡単に言ってしまえばバッファに音を詰め込んでそこから取り出すだけなので、データ構造として何を選ぶかがキモになります。
FIFOかつ決まった秒数のサンプル数を保持できればいいので、サーキュラーバッファ(リングバッファ)がよく選ばれるそうです。
素のC++だとサーキュラーバッファを扱えないので、別途Boostを入れます。
サイズの管理を自分でやるのであればstd::dequeとかでも良い気がします。
あとJUCEにはAudioBufferクラスっていうのが存在するみたいなので、それが一番いいのかもしれません(不勉強)。

バッファはチャンネル毎に必要なので、vectorに入れてみる。

余談:Boost

Boostはネットで拾ってきてうまいことコンパイルする。
自分は↓をみてやった。
programming-aip.blogspot.jp
コンパイルに関して、

Visual Studioコマンドプロンプトを開くか,普通のコマンドプロンプトを開いて64ビット版をビルドしたければ,"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"を実行する.

と書いてるけど、コンパイラへのパスが通っていないといけないので前者が良いと思う。
開発者コマンドプロンプトってやつです。

あとはProjucerでDebugやReleaseのHeader search pathsとExtra library search pathsにそれぞれのパスを設定すれば使える。

余談:DelayLine

DelayLineはプログラム的にはただのバッファなんだけど、アナログの世界だとほんとに線なので面白いです。
Analog delay line - Wikipedia

PluginProcessor.cpp

void DelayAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    sampleNumPerDelayTime = delayTimeMiliSec / 1000.0f * sampleRate;
    while (delayLine.size() < getTotalNumInputChannels())
    {
        delayLine.push_back(boost::circular_buffer<float>(sampleNumPerDelayTime * repeatNum));
    }
}

prepareToPlayでVSTホストの情報を使った初期化処理を書く。
sampleRateは単位秒ごとのサンプル数(44,100とか)なので遅延時間を掛けると確保すべきバッファ長が分かります。
更に繰り返し回数を掛けてバッファを確保する。

void DelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    const int totalNumInputChannels  = getTotalNumInputChannels();
    const int totalNumOutputChannels = getTotalNumOutputChannels();

    for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
    {
        buffer.clear (i, 0, buffer.getNumSamples());
    }

    for (int channel = 0; channel < totalNumInputChannels; ++channel)
    {
        float* channelData = buffer.getWritePointer (channel);
        for (long buffNum = 0; buffNum < buffer.getNumSamples(); buffNum++)
        {
            delayLine[channel].push_front(channelData[buffNum]);
            for (int i = 1; i <= repeatNum; i++)
            {
                if(delayLine[channel].size() < sampleNumPerDelayTime * i) break;
                channelData[buffNum] += (0.5f / i) * delayLine[channel][sampleNumPerDelayTime * i - 1];
            }
        }
    }
}

一番深いネストの部分がディレイの部分。
(クラスを作ったほうが良いという意見も当然あると思うけど、短かったので。。。)

push_frontでサンプルをバッファに入れているので、begin側が新しいサンプル、end側が過去のサンプルになります。
例として、遅延時間を1秒、繰り返し回数を3回、サンプリングレートを44,100とすると、バッファの中身は以下の様になります。
delayLine[channel][44099] :1秒前のサンプル
delayLine[channel][88199] :2秒前のサンプル
delayLine[channel][132299]:3秒前のサンプル
なのでこれらを原音に足し込んでいくとディレイするようになります。

足し込む際の減衰はボリュームカーブの実装をちゃんと考えないといけないです。
さすがにコレ(0.5f/i)は適当すぎる。
ちゃん作り込むとなると、繰り返し回数が全部聞こえるようにカーブを設定しないといけないと思う。

サンプル

鳴らしてみるとこんな感じになります。

参考

JUCE JAPAN vol.1: JUCEではじめるVST/AUプラグイン制作(Windows/MacOS対応)

JUCE JAPAN vol.1: JUCEではじめるVST/AUプラグイン制作(Windows/MacOS対応)

www39.atwiki.jp


またなにか作ったら書きます。

2016年のまとめと2017年のこと

セーフなうちに書きましょう。

仕事

新卒で3年と少し(40ヶ月)勤めた会社を辞めました。
所謂ブラックだったので辞めるのにも一苦労、といった感じでしたが、懇意にしてもらっていた上司に連れられる形で脱出しました。
ひとまずは落ち着いた環境で過ごせています。
腰掛けというと言葉が悪いですが、自分がやりたいことをやれるようになるまで預かるだけだからなと上司からも念を押されているので、独り立ちできるように準備中です。

プライベート

プロダクト

自分の時間が持てるようになったこともあり、いくつか作りました。

デジマート中古ギターアーカイブ

デジマート中古ギターアーカイブというサイトを作りました。
f:id:delatetei:20170106211052p:plain
国内最大の楽器検索サイトであるデジマートに登録された中古ギターの情報を保存しています。
半端ない数のギターがデジマートを介して取引されているのですが、商品が売れたら商品ページが削除されてしまうため、貴重な情報があっという間に失われてしまいます。それを惜しく思ったので作成。

検索機能がメインですが、ウリとして魚拓代わりのスクリーンショットを取得しています。


技術的な話を以下つらつら。

・サーバー構築
VPSを借りて一からやった。
ウェブ系はからっきしなので外向けのサーバ構築はだいぶ骨が折れた。
でも勉強になった。

・サイト
RoRに初挑戦。サクサク作れて楽しい。

・クローラ
Rubyによるクローラー開発技法」を片手にRubyで書いた。
時間帯によるアクセス頻度の調整はcronから呼ぶシェルでうまいことやってます。

スクリーンショットの取得
PhantomJSで取得。
動作時に読み込ませるjsファイルはperlでガリガリ自動生成した。
その後はpngquantで圧縮。

デジマート中古ギターアーカイブ(TwitterBot)

デジマート新着中古ギター情報
f:id:delatetei:20170106214636p:plain
上記サイトでスクレイピングした情報をついでにTwitterBot投稿。
“おまけ”のつもりだったのですが、明らかにこっちの方が利用者が多いです。
(フォロワー約1,200人)

たまに面白いギターが登録されると、RTで自分にも回ってきたりします。
こういうのとか


中古楽器入荷速報

f:id:delatetei:20170106222814p:plain
楽天に登録された中古楽器の情報を流すBot
楽天アフィとAPIで小銭稼ぎできないかな~と思って作った。
Twitterに直接アフィURLを貼ると短縮URLに変換されて規約違反になるので、自前のWordpressに誘導するという酷いユーザーエクスペリエンス。
毎月1,000~2,000円程度は稼いでくるので、VPS代は賄えている。と思う。

一応、本気でアフィをやってみた感想として、自分の性格に合わない、投入労力に見合わないというのが分かったのが収穫。
これでアフィに未練はないです。

その他

投資を始めました。

ブラック企業時代は
仕事でストレスを受ける→金遣いが荒くなる→貯金がないから辞めるに辞めれない
という酷いループに陥っていました。
最終的に一文無しで転職することになって苦労したので、貯金がてら投資信託をやっています。

また、夏を過ぎた頃から日経平均の地合いも良くなっていたので、少額で個別株を買って勉強したりもしています。

元本が少ないので儲けも微々たるものですが、お金の入り口が増えることによる精神的な安心は思ったより大きいです。
(当然、リスクもありますが)お金のない人こそ投資の勉強をしてもいいんじゃないかなって思います。

まとめ

転職や投資の勉強をしたことによって自分の時間が作れるようになったので、2017年はどんどんモノ作りしていきたいと思います。
ブログもちゃんと書きます!

それではよろしくお願いします~

Java SE 8 Programmer I (1Z0-808:Java Silver)に合格しました

Java Silverに合格したので所感を述べます。

受験のきっかけ

Javaでの開発経験を信用してもらえなかったから

IT土方としてプロパーさんと面談する際、技術的な話はあまり聞いてもらえない。
SI業界だと人売りが経歴を盛ることも珍しくないから、年齢が若いとコミュニケーション能力があるかどうかに話が行きがち。
開発経験を口だけで語っても胡散臭く思われるだけなので資格取得を決めた。

ざっくりした経歴

社会人4年目。
C on Vim on Unix(Linux)で制御系の開発をやってた。
実務でのJavaはSwingをちょこっと触ったことがある程度。

勉強時間

40時間ぐらい。

教材

いわゆる紫本と黒本。
最初は紫本だけで臨もうとしていたけど、念のために黒本を買ってみたら全然解けなくて大慌て。

黒本は問題が良く出来ていて、理解が甘い所をピンポイントで突いてくるからすごく勉強になった。
ほとんど同じ問題が実際の試験でも出題されるので、進研ゼミ状態。

紫本は本としての質がそもそも低いと思った。
出題範囲についてざっくりとは分かるだろうけど、本質的に理解ができるかというと???
amazonでも概ね評価が良いように見えるが、“赤点ギリギリだけど試験に合格できたから星5つ”みたいなレビューが多い時点でお察し。
Javaを触ったことがないような人だといいかも知れない。それでも黒本と併用したほうがいいと思う。

分厚い本を何周もする気になれなかったし、手応えがあったから各々一周読んで受験した。

受験の申し込み

  • Oracleのページ分かり辛い
  • ピアソンのページも分かり辛い

チケットは楽天で買ったほうが(2000円ぐらい)安いです。
ピアソン的には試験会場の予約と同時に買わせたいみたいで、試験を選択した時点で正規の金額が画面に表示されます。
ページを進めていくとバウチャーを入力する箇所があるので、買ったチケットのコードを入力すれば問題なし。
金額が差し引かれるのでピアソンでもお金を払うようなことにはなりません。
下はアフィリンク

試験会場の話

  • ベンダー資格は受けたことがなくて、テストセンターでの受験も初めてだったから緊張
  • 電子署名したり顔写真をwebカメラで取られたりハイテク
  • 椅子が想像より低かったせいで座る際に受験スペースで転けそうになる

試験中の話

  • 難易度は黒本より低い
  • 手応えはあったけど、受験料が高いこともあって結構プレッシャー
  • イヤーマフをつけると周りの音が聞こえない代わりに自分の心音が聞こえるから焦ってるのが分かって微妙
  • ホワイトボードは渡されるけど、イレイサーはない。書きっぱなし。
  • 渡されたペンのインクの出が悪くてイライラ
  • PC画面を見ながら問題を解くのは疲れる
  • インデントがおかしい問題があって???
  • 全問解いた時点で30分残っていたけど、気力が残っていなかったのでとっとと退出

受験後の話

  • 採点結果は試験終了から7分程度ですぐ来た
  • 正解率94%で合格

これから

本当はC++案件やりたい