2020年8月29日土曜日

Studio One 5 ArtistでScales & Chords (Reason 11 LiteのRack Plugin) を使う

音楽のコード(和音)の生成規則はわかったけれど、鳴らそうとすると腰が重くなる。でも鳴らさないとどんな音かわからない。好きな音源でルート(根音)と生成ルールを指定したら該当するコードを鳴らしてくれたらいいのに!

これをPresonusのハードウェア製品 (例えばオーディオインタフェースStudio c24) にバンドルされているDAW Studio One 5 Artistで、KORGのMIDIキーボードmicroKey-25にバンドルされているReson Lite 11のScales & Chordsで実現する方法。

Studio One 5 Prodessionalならコード・トラックがあるのできっと不要のノウハウ。コードを覚えていない初学者でも楽にそれっぽい音を鳴らしたいと思ってあれこれ試した結果。

しばらくしたら忘れそうなので覚書として残しておく。


Studio One 5 ArtistがVST3対応し、Reason 11 LiteにReason Rack Plugin(VST3プラグイン)が含まれるようになったので、下記の手順で実現できる。
  1. Reason Rack PluginでScales & Chordsのインストゥルメンタルトラックを作る
  2. 鳴らしたい音源のインストゥルメンタルトラックを作る
  3. 新規インストゥルメンタルトラックを作成し、次のとおり入出力を設定する
    • 入力:Reason Rack Plugin | Event Out
    • 出力:既存のインストゥルメント > 「2」で作ったインストゥルメンタルトラック
  4. 「3」で作ったインストゥルメンタルトラックを選択した状態でキーボードのルートを押す

Scales & Chordsよりあとで見つけたChordSpace Homeの方が使い込み甲斐があるかも知れない。各音のベロシティを変えられたりと細かく制御できる。

もっといいやり方があったら@SO_Cにリプライください。

2017年10月21日土曜日

JShellを使ってJavaだけでSelenium (ChromeDriver) を動かす。

はじめに

Mirror House Lab: Nashornを使ってJavaScriptを書いてSelenium (ChromeDriver) を動かす。で、
「もうすぐjshellを含むJava SE 9がリリースされてJavaをスクリプトとして実行できるようになるだろうに、何をやっているんだ」という気もしているけれど、Java SE 8環境ですぐに動かしたかったので。
と言っていた。

Java SE 9がリリースされたのでJShellで動かす方法について書く。

環境と準備

環境は以下の通り。
  • OS: Windows 10 (64bit)
  • JDK: 9
  • Selenium Standalone Server: 3.6.0
  • Chrome: 61
  • ChromeDriver: 2.33

SeleniumとChromeDriverの準備作業は変わらない。ただしNashhornとJShellでクラスパスの通し方が異なる(後述)。JDKとChromeはインストール済みとする。

Selenium: DownloadsからSelenium Standalone Serverをダウンロードする。保存先フォルダにパスを通すのは必須ではない。JShellはオプションでもコマンドでもクラスパスを指定できる。この記事ではコマンドで指定する方法を採用する。

ChromeDriver: Downloads - ChromeDriver - WebDriver for Chromeから、chromedriver_win32.zipをダウンロードして展開する。Windows 64bit用は提供されていないので32bit用を使う。こちらも保存先にパスを通すのは必須ではない。Javaの場合、プロパティに設定できる。このエントリィではその方法を採用する。

サンプルコード

クラスパスを通すのはJShellのコマンド。あとはJavaなので取り立てて言うことはない。
// jshell-selenium.jsh
/env -class-path C:\path\to\selenium-server-standalone-3.6.0.jar;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

String pathToChromeDriver = "C:\\path\\to\\chromedriver.exe";
System.setProperty("webdriver.chrome.driver", pathToChromeDriver);

ChromeDriver driver = new ChromeDriver();
driver.get("http://www.google.com/xhtml");
Thread.sleep(5000);
WebElement searchBox = driver.findElement(By.name("q"));
searchBox.sendKeys("ChromeDriver");
searchBox.submit();
Thread.sleep(5000);
driver.quit();

実行方法

最初はJShellを起動して、下記を実行する。
> /open C:\path\to\jshell-selenium.jsh

2回目以降、そのまま繰り返すときは/reloadコマンド。

スクリプトファイルを修正して再実行するなら、/resetコマンドを実行してから、/openコマンド。JShellは/listで表示されるコードを実行するのだけれど、/openコマンドは追記して実行するので、もう1回/openコマンドでスクリプトファイルを読み込むと2回実行される。

クラスパスの通し方

クラスパスは、JShell起動時にコマンドラインオプションで渡すこともできる。External Codeの"Setting The Class Path"を参照。

Java 9なのでクラスパスではなくてモジュールも使える(External Codeの"Setting Module Options")。でも、そのモジュールをまだよく分かっていないので、まずはそちらから調べないと。

感想

Javaで書けるので言語差分を考えなくてよいのと、ちょっとデバッグしているときにJShell上で補完が効くのが助かる。

References

2017年7月15日土曜日

Nashornを使ってJavaScriptを書いてSelenium (ChromeDriver) を動かす。

はじめに

開発環境ではない環境で、ちょっとしたブラウザ操作を自動化するのに使った方法について書く。

具体的には、Nashorn (Java SE 8で追加されたJavaScriptエンジン。Rhinoの後継) を使い、JavaScriptを書いてSelenium Standalone Serverを呼び出し、ChromeDriverでChromeを自動操作する方法。

「Selenium Standalone ServerはJarなのだから、素直にJavaから呼んだら?」とか、「JavaScriptで書くならSelenium Client & WebDriver Language BindingsのJavaScript (node)を使うのが自然では?」とも思うのも、ごもっとも。自分もそう思う。

それでもこの方法を調べたのは、環境準備が楽だから。JREさえインストールされていれば、あとはSeleniumをダウンロードするだけ。Eclipse, JDK, node.jsどれも必要ない。

「もうすぐjshellを含むJava SE 9がリリースされてJavaをスクリプトとして実行できるようになるだろうに、何をやっているんだ」という気もしているけれど、Java SE 8環境ですぐに動かしたかったので(※2017/10/21追記: JShellでも動かしてみた)。

環境と準備

環境は以下の通り。
  • OS: Windows 10 (64bit)
  • JRE: 8
  • Selenium Standalone Server: 3.4.0
  • Chrome: 59
  • ChromeDriver: 2.30

SeleniumとChromeDriverの準備作業は以下の通り。JREとChromeはインストール済みとする。

Selenium: DownloadsからSelenium Standalone Serverをダウンロードする。保存先フォルダにパスを通すのは必須ではない。Nashornを起動するときにオプションでクラスパスを指定できる。この記事ではその方法を採用する。

ChromeDriver: Downloads - ChromeDriver - WebDriver for Chromeから、chromedriver_win32.zipをダウンロードして展開する。Windows 64bit用は提供されていないので32bit用を使う。こちらも保存先にパスを通すのは必須ではない。Javaの場合、プロパティに設定できる。このエントリィではその方法を採用する。

サンプルコード

ポイントはJavaクラスへのアクセス。標準JavaパッケージのクラスにアクセスするにはFQCNを使う。それ以外のクラス(ここではorg.openqa.seleniumパッケージのクラス)にアクセスするには、Java.type('FQCN')を使う。
// nashorn-selenium.js

// グローバル変数/関数を作らないため即時関数呼び出し。
// 『メンテナブルJavaScript』の「6.4 0-グローバルのアプローチ」参照。
// この使い方の場合、ここまでする必要もないかもしれないけれど一応。
(function() {
  var ChromeDriver, By;
  var pathToChromeDriver, driver, searchBox;

  // Javaのimport相当。
  ChromeDriver = Java.type("org.openqa.selenium.chrome.ChromeDriver");
  By = Java.type("org.openqa.selenium.By");

  // chromedriver.exeへのパスをプロパティに設定。
  // chromedriver.exeが環境変数PATHに指定しているフォルダにあるなら省略できる。
  pathToChromeDriver = 'C:\\\\path\\to\\chromedriver.exe';
  java.lang.System.setProperty('webdriver.chrome.driver', pathToChromeDriver);

  // 実行内容は、
  //   Getting started - ChromeDriver - WebDriver for Chrome
  //   https://sites.google.com/a/chromium.org/chromedriver/getting-started
  // と同じ。
  // Chromeを起動して、Googleで"ChromeDriver"を検索して、Chromeを終了する。
  driver = new ChromeDriver();
  driver.get('http://www.google.com/xhtml');
  java.lang.Thread.sleep(5000);
  searchBox = driver.findElement(By.name('q'));
  searchBox.sendKeys('ChromeDriver');
  searchBox.submit();
  java.lang.Thread.sleep(5000);
  driver.quit();
}());

実行方法

コマンドプロンプトからjjs (nashornを起動するツール) を実行する。その際、-cpオプションでSelenium Standalone Serverをクラスパスに追加しておく。
> jjs -cp "C:\path\to\selenium-server-standalone-3.4.0.jar" nashorn-selenium.js

感想

もろもろの補完が効かないから、スクリプトを書くのが疲れる。けれど、IDE入れるなら環境を整えて、Javaから動かせばよいので、どちらの手間を惜しむかか。

References

2016年11月11日金曜日

設計アプローチ (POA/DOA) 再考

最近、業務システムの設計の流れについて考えている。自分の頭の整理のため、それを書き出してみた。結論だけ乱暴に言うと、ユーザと設計を始める取っかかりはUI。でも、並行して既存データも分析する必要がある。その結果、最初に設計が安定してくるのがデータで、そこからUIや機能にフィードバックされる流れになるだろうと考えている。

2つの設計アプローチ

業務システムの設計アプローチとして、POA (Process Oriented Approach)とDOA (Data Oriented Approach)という考え方がある。POAでは業務プロセスつまり仕事の手順から手をつけていく。DOAではデータつまり帳簿から手をつけていく。

自分には、DOAの方が理に適っていると思える。一般的な傾向として、業務プロセスよりデータの方が安定しているし、変更の影響が大きいからだ。だからデータベースに早めに安定した設計を与えたい。そうしないと、プログラミングできない。
データ構造がダメな状態で、プログラミングによって挽回することはできません。
――『達人に学ぶDB設計』
『データベース・リファクタリング』にもどうようの主張があった。

機能が先かデータが先か

ところが、先日『はじめよう!要件定義』を読んでいたら、UI・機能・データを、
  1. 何はともあれUI
  2. 操作に対して機能が動作すること
  3. 機能に必要なデータ揃っていること
の順で設計していっている。確かに、ゴールから逆算するとこうなる。『実践テスト駆動開発』からの孫引きだが、こんな言葉もある。ユニットレベルの粒度で考えても、データアクセスレイヤをモック化するのはユニットテストの常套手段だ。
何かを設計するときには、常にもうひとまわり大きなコンテキストの中で考えること。椅子ならば部屋の中にあることを考える。部屋なら家の中、家なら環境の中、環境なら都市計画の中。
――エリエル・サーリネン

並走すればいい

データモデリングの視点で見ると、これはトップダウンアプローチだ。普通は、これだけでは足りない。既存データがあるからだ。そこには、UIには表れない、他のシステムから連携されるデータが格納されているかもしれない。過去の業務プロセスに由来する、今は使わないデータが格納されているかもしれない。ここで、ボトムアップアプローチつまり既存データの分析も必要になる。

ボトムアップアプローチでデータが変わるとどうなるか。既存データは変えられないから機能やUIにフィードバックがかかることになる。絵にするとこのようなイメージ。これならしっくり来る。


データベース恐怖症?

ここからは設計を離れて人の話。UIや機能の分析と、既存データの分析を一人で両方やる必要はないにしろ、最終的には統合して一貫した設計に仕上げないと動かない。だから、分担して情報交換することになる。そのときのことを考えると、もう少しデータベース設計の知識が広まるといいな、と思う。

データベース設計をできてプログラミングできない人は見たことがないけれど、逆はよく見かける。漢(オトコ)のコンピュータ道: データベースについてのそもそも論や『SQLアンチパターン』を見ると、隔たりは大きそうだけれど。

refernces


2015年10月17日土曜日

Windows10でRedPen (CLI) を使う

マニュアルなどの文書チェックツールRedPenをWindows10のコマンドラインから使う方法について記載する。Windows環境で動かそうとしたら2, 3引っかかったので、その解消方法メモ。あと、オマケとしてサクラエディタで編集中のファイルをチェックする方法も。

利用環境は次のとおり。
  • RedPen 1.4.0
  • Windows 10
  • Java 1.8.0 update 45

1. インストール

Java 1.8.0以降をインストールしておく。環境変数JAVA_HOMEも設定しておくこと。

リリースページから、redpen-1.4.0.tar.gzをダウンロードして、任意のフォルダに展開する。以降、展開したフォルダをINSTALL_DIRと表記する。

2. 微調整

そのまま実行すると次の2つの問題があるので、微調整する。
  • チェックメッセージが文字化けしている。
  • カレントディレクトリにjsフォルダが作成される。
文字化けを解消するには、INSTALL_DIR\bin\redpen.batの12行目に-Dfile.encoding=UTF-8を追加する。これでチェックメッセージの文字化けが解消する (コマンドプロンプト上だと、代わりに実行ログが文字化けしてしまうけれど許容している)(完全には解決できなかったのが気持ち悪いけれどIssueを出してみた)。
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8
jsフォルダの作成を抑止するには、設定ファイルINSTALL_DIR\conf\redpen-conf-ja.xmlの<validator name="JavaScript" />を次のように書き換える。JavaScriptで実装されたチェックルールを使う予定がないなら、代わりに消しても良い。
<validator name="JavaScript">
    <property name="script-path" value="INSTALL_DIR\js" />
</validator>
メモ: Writing RedPen extension with JavaScript | RedPen BLOGRedPenのValidatorをJavaScript で書くには - ククログ(2015-08-29)を読むと、プロパティscript-pathが優先で、未指定なら環境変数REDPEN_HOME\jsを参照しそうなものだけれど、未指定だとカレントディレクトリ\jsを参照しようとして存在しないときは作成してしまうみたい (このコミットを見ると、次のヴァージョンではログが出るだけになりそう)。詳しい原因は不明。環境変数REDPEN_HOMEはredpen.bat内で設定されているから、設定漏れではなさそう。redpen.batにecho %REDPEN_HOME%を追記してみたら、ちゃんとINSTALL_DIRが表示されるているし (ForkしてUnit Testを書いてみたけれどNGだったので、Issueを出してみた)。

3. 実行確認

任意のディレクトリ (微調整の確認のため、最初はINSTALL_DIR以外がよい) でコマンドプロンプトを実行し、次のコマンドを実行する。
INSTALL_DIR\bin\redpen -c INSTALL_DIR\conf\redpen-conf-ja.xml INSTALL_DIR\sample-doc\ja\sampledoc-ja.txt
下記のような実行結果が表示されるはず。
(前略)
[2015-10-17 20:15:52.673][INFO ] cc.redpen.validator.JavaScriptValidator - JavaScript validators directory: INSTALL_DIR\js
sampledoc-ja.txt:1: ValidationError[SentenceLength], 文長("101")が最大値 "100" を超えています。 at line: 最近利用されているソフトウェアの中には複数の計算機上で動作 (分散)するものが多く存在し、このような分散ソフトウェアは複数の計算機で動作することで大量のデータを扱えたり,高負荷な状況に対処できたりします。
(以下略)

(オマケ) サクラエディタで編集中のファイルのチェック

[ツール] > [外部コマンドを実行]で、下記の通り設定して[実行]ボタンを押すと、編集中のファイルをチェックできる。一度実行すれば、Ctrl+F, Enterでチェックできて便利。
名前: "INSTALL_DIR\bin\redpen.bat" -c "INSTALL_DIR\conf\redpen-conf-ja.xml" "$F"
標準出力を得る: チェックボックスをオンにして"UTF-8"を選ぶ。
標準出力リダイレクト先: アウトプットウィンドウ
ちなみに、アウトプットウィンドウ上だと実行ログもチェックメッセージも文字化けしない。

2015年8月9日日曜日

テストデータを管理する方針

『継続的デリバリー』の、テストデータの管理についての記述を整理してみた。該当する章節は、
  • 12.5 テストデータを管理する
  • 12.6 データの管理とデプロイメントパイプライン
それから12.5から参照されている、
  • 8.5.1 受入れテストにおける状態
の3箇所。特に断りの無い限り、『継続的デリバリー』のいう受入れテストのデータ管理を念頭に置いている。

テストデータの管理で問題となるのは、1) パフォーマンス、2) テストの分離の2つ。xUTPだとそれぞれSlow TestsSeparation of Concernsに対応しているように思う。

どちらの問題でも、真っ先に原因として挙がるのがデータベース。ユニットテストならデータベースアクセス移譲先 (デザインパターンDAO相当) をテストダブルで置き換えられる。これはパフォーマンスにも分離にも効く。DBの状態も含めてテストしたい場合、インメモリDB (H2, SQLite, JavaDBなど) を使うこともできる。

データベースに限らず、テストとデータのつながりを管理するアプローチには、次の3つがある。
  1. テストの分離: 各テスト用のデータは、そのテストからしか見えないようにする。
  2. 順応型テスト: テストがデータ環境を調べ、実際のデータに合わせて振る舞うようにする。
  3. テストの順序づけ: テストの実行順序を予め決めておいて、一つ前のテストの出力を次のテストの入力とする。
スケールするのは1だけだと言っている。3は分かりやすい無理ゲー。こんな強く依存していたらスケールさせられない。2は一見良さげに見えるけれど、分離しきれていないと、別のテストで実際のデータが思いもよらない状態になっていることがある。xUTPでもTest SmellsとしてConditional Test Logicが挙がっている。

「テストの分離」のためには、まずテスト終了時にテスト前の状態に戻すとある。そうしないと、次のテストに今のテストのデータが見えてしまう。ただこれにはオプションもある。『システムテスト自動化標準ガイド』や『実践テスト駆動開発』では、テスト対象が登録したデータはテスト終了時に消さずに、テスト開始時に消すことを勧めている。もう一つの方法は、データを機能分割すること。これができるかどうかは、テスト対象の特性に強く依存する。

データを分割し、巨大で複雑なデータ構造への依存を減らすには、まずデータを整理しないといけない。著者はこんな風に言っている。
何よりもまず、プロダクションデータのダンプを取得して受入れテスト用にテストデータベースに投入したいという誘惑に負けないこと。
統制のとれた最小限のデータセットを保守しよう。
整理の取っかかりとなるのが、次の3種類のデータの区別。
  1. テスト固有のデータ: 一意でなければならない。テストの分離の手段になる。
  2. テストが参照するデータ: テストには関係するがふるまいには影響しないデータ。そこら中で使われるマスタデータ類を指していると思う。
  3. アプリケーションが参照するデータ: アプリケーションを立ち上げるのに必要なデータ。

一言で言うと、正しく動くと分かっている(契約による設計の言葉を使うと、事前条件を満たしている)開始位置を特定し、テスト開始時にその状態を復元する。言ってしまえばこれだけなんだけれど、そのためにはテスト対象とテストデータをよく理解する必要がある。それも一部のテストだけじゃない。うまくテストを分離するには、全体を俯瞰する必要がある。

なお、その開始位置を復元するのには、アプリケーションのAPIを利用するよう勧めている。理由は3つ。
  • システムを矛盾した状態に持ち込ませない。
  • データベースやAPIのリファクタリングの影響を避けられる。
  • APIのテストにもなる。
できないときは、事前条件をアサートする防御的なテストコードにしたり、アサートを相対的(例えば、レコードが3件あることではなくて、3件増えたことにする)にしたりする。

References


2015年8月2日日曜日

JUnitのRunner (Enclosed, Theories, Categories) を併用したときの動き

JUnit4の次のRunnerの関係を整理してみた。なお、JUnitのバージョンは4.12。
  • Enclosed
  • Theories
  • Categories

論理的にテストクラスを分類しつつ、並列化するための分類もしたくなることがあるので、JUnitの仕組みでどこまでできるか知っておきたくて。

では、早速。

EnclosedとTheoriesは併用できる。外部クラスEnclosingTheoryをJUnit実行すれば、内部クラスEnclosedTheoryがJUnit実行される。これでTheoriesを使いたいけれど、テストクラスを分けたくない場合は大丈夫。
@RunWith(Enclosed.class)
public class EnclosingTheory {
    @RunWith(Theories.class)
    public static class EnclosedTheory {
        @Theory
        public void testTheory(Fixture f) throws Exception {
            // test method.
        }
    }
}

EnclosedとCategoriesは併用できない。外部クラスEnclosingTheoryにカテゴリOuterを付けて、Categoriesを使ったテストスイートを実行しても、テストが見つからない。
@RunWith(Enclosed.class)
@Category(Outer.class)
public class EnclosingTheory {
    @RunWith(Theories.class)
    public static class EnclosedTheory {
        @Theory
        public void testTheory(Fixture f) throws Exception {
            // test method.
        }
    }
}
@RunWith(Categories.class)
@IncludeCategory(Outer.class)
@SuiteClasses(EnclosingTheory.class)
public class CategorizedTestSuite {
    // NoTestsRemainException is thrown.
}

ただ、内部クラスEnclosedTheoryを直接指定すれば、実行させられる。Enclosedの甲斐がないと見るか、互いに独立した分類が使えると見るか、悩ましい。
@RunWith(Enclosed.class)
public class EnclosingTheory {
    @RunWith(Theories.class)
    @Category(Inner.class)
    public static class EnclosedTheory {
        @Theory
        public void testTheory(Fixture f) throws Exception {
            // test method.
        }
    }
}
@RunWith(Categories.class)
@IncludeCategory(Inner.class)
@SuiteClasses(EnclosedTheory.class)
public class CategorizedTestSuite {
    // run testTheory.
}

上記でテストが実行されるので、CategoriesとTheoriesは併用できることが分かる。

調べて見ると、CategoriesとEnclosedはそれぞれSuiteのサブクラスだった。併用できないのもさもありなん。

以下は、調べながら考えたことをつらつらと。

こうして調べて見ると、Categoryアノテーションで並列化のための分類をするのは筋が悪い気がしてきた。MECEに分割したいのだけれど、アノテーションの付け忘れやテストスイートへの追加忘れがありそう。何並列にするかによるけれど、上位のパッケージ構成でざっくり割っちゃった方が安全かなぁ。

CIとの相性も考える必要がある。AntのJUnitタスクから実行するなら、パッケージ構成やファイル命名規約に加えてFileSetで色々できる(開発端末上では使えないけれど)。一方、MavenはCategoryにも対応している。そろそろAntから卒業した方がいい気がしてきた……。

なお、調べるために書いたコードはso-c/junit4.12-categories-configuration-sampleにアップしてある。ここに書いたスニペットよりゴチャゴチャしているけれど、ちゃんと動くのでこれはこれで。