「 プログラミング 」一覧

Scala でソフトシンセ作ってみる その1 波形生成

まずは波形生成。アナログシンセでいうところのオシレータ(OSC)にあたります。

ソースコードはこちら。ひとまずデューティ比可変の矩形波と、正弦波、三角波に対応しています。

https://github.com/shout-poor/Synthcala/blob/master/Synthcala/src/jp/noisyspot/synth/gen/WaveGenerator.scala

Java だと、オシレータの抽象クラスを作って、波形別に実装クラスを作って、パラメータをメンバ変数に持たせて…とかやるんですが、ここでは関数型らしく、パラメータを与えると、「パラメータに応じた波形を生成する関数」を返してくれる高階関数として実装しました。

例えば正弦波の場合はこんな感じ。

  def sineWave(sampleRate: Double, tone: Double) = (z: Int) => {
    import scala.math._
    sin(pInWave(sampleRate, tone, z) * 2.0 * Pi)
  }

サンプルレートと周波数を渡してあげると、時間変数 z (サンプリングレートの逆数を単位とする変数)を引数とする関数が帰ってきます。その関数を、例えばRange.mapに与えてあげると、一定時間内での波形をサンプルのリストとして取得できます。

scala>  val sinConc=sineWave(100, 20) // サンプリングレート 100Hz, 音程20Hz
sinConc: Int => Double = <function1>

scala>  Range(0, 100).map(sinConc)
res0: scala.collection.immutable.IndexedSeq[Double] = Vector(0.0, 0.9510565162951535, 0.5877852522924732, -0.587785252292473, -0.9510565162951536, 0.0, 0.9510565162951535, 0.5877852522924736, -0.5877852522924734, -0.9510565162951536, 0.0, 0.9510565162951539, 0.5877852522924736, -0.5877852522924734, -0.9510565162951539, 0.0, 0.9510565162951539, 0.5877852522924736, -0.5877852522924734, -0.9510565162951539, 0.0, 0.9510565162951539, 0.5877852522924714, -0.5877852522924712, -0.9510565162951539, 0.0, 0.9510565162951539, 0.5877852522924714, -0.5877852522924712, -0.9510565162951539, 0.0, 0.9510565162951539, 0.5877852522924714, -0.5877852522924712, -0.9510565162951539, 0.0, 0.9510565162951539, 0.5877852522924714, -0.5877852522924712, -0.9510565162951539, 0.0, 0.9510565162951522, 0.58778525229247...

で、これらとは別に、モノラル音声を任意の定位でステレオの左右に振り分ける関数返す pan と、与えられた係数をかける関数を返す vol 関数を作成しました。これらで得られる関数を andThen で合成することにより、任意の定位、音量の音声波形を得る関数をクライアント側で作成できます。

クライアント側はこんな感じ。

// 音程440Hz、音量0.5、定位0.2 の矩形波関数
val sineConcrete = sineWave(FRAMES_PAR_SEC, 440.0) andThen vol(0.5) andThen pan(0.2)
val samples = Range(0, FRAMES_PAR_SEC).flatMap(sineConcrete)

pan で得られた関数の戻り値は、2ch分のサンプルを持つ Seq なので、先ほどと違って Range.flatMap で展開しています。

こんな風にしてえられた samples を、前回作成した OutDevice に出力すれば、めでたくパラメータ通りの音が鳴る、ということになります。

というところで今回は終了。次回はSMFライクなシーケンスデータで発音タイミングや音程を制御するあたりをやろうと思います。


Scala でソフトシンセ作ってみる その0

なんか前も同じようなこと書いた気もするけど、以前挫折したのをやり直したりしています。

とりあえず、今回は wav に吐いて終わりではなく、ちゃんと自力で音を出せるように、まずはデバイスへの出力クラスから作ってみました。

https://github.com/shout-poor/Synthcala/blob/master/Synthcala/src/jp/noisyspot/synth/out/OutDevice.scala

使う方はこんな感じ。 440Hz の矩形波を生成して出力するサンプルです。

https://github.com/shout-poor/Synthcala/blob/master/Synthcala/testrunner/OutDeviceTestRun.scala

ポイントとしては、

  • SourceDataLine#write は、内部バッファがいっぱいになると空きができるまでブロックするので、再生自体を別スレッドで処理するために Actor を継承。メッセージとして直接サンプルのリスト (Seq[Double]) を送信して使用する。
  • ソフトシンセの波形生成側で扱うサンプルは -1.0 ~ 1.0 の倍精度実数とし、本クラス内でデバイスに応じたバイト列に変換。(現時点では、符号付き 16bit / LittleEndian のみ実装)

基本的には Java の Audio API を使ってるだけなので、Scala らしいところはあんまりないかと思います。

次は波形生成と各種フィルタ/エフェクタの枠組みを作っていきます。




JScriptでExcelブックを操作

Windows Scripting Host では、デフォルトで VBAライクな VBScript と JavaScript ライクな JScript が動きます。ActiveXObject クラスを使うと、Excel.Application のようなOLEオブジェクトも扱えるので、JScript で Excel マクロ的なものも書けます。

Excel ブックと一体で扱いたい時は相変わらず VBA しか選択肢がないのですが、大量ファイルを一括処理するバッチなどは JScript で書いたほうが何かとやりやすいです。

というわけで備忘録的サンプル。 

/* WSH Script: JScriptからExcelブックを操作する例 */
/* 全シートのヘッダ/フッタを全部消す              */

/**
 * Operation for a worksheet
 * -- Erace all headers and footers of the sheet.
 */
function sheetOp(sheet) {
    var ps = sheet.PageSetup;

    ps.PrintArea = "";
    ps.LeftHeader = "";
    ps.CenterHeader = "";
    ps.RightHeader = "";
    ps.LeftFooter = "";
    ps.CenterFooter = "";
    ps.RightFooter = "";

}


/**
 * Get ActiveX Excel object
 */
function getExcelApplication() {
    var excel = new ActiveXObject("Excel.Application");
    return excel;
}

/**
 * main loop
 */
function main(filename, sheetOp) {
    var excel = getExcelApplication();
    var book = excel.Workbooks.Open(filename, true, false);
    try {
        var sheets = book.Worksheets;
        for (var i = 1; i <= sheets.Count; i++) {
            sheetOp(sheets.Item(i));
        }
    } finally {
        excel.DisplayAlerts = false;
        book.Close(true);
        excel.Quit();
    }
}

var args = WScript.arguments;
var filename = args(0);
main(filename, sheetOp);

Meadow + Gauche セットアップメモ

Windowsで、emacs(Meadow) 上で Gauche を使えるようにするためのメモ。 Meadow 3.01-dev と Gauche 0.9.2 の組み合わせで確認しています。

  1. Meadow をインストールする
    http://www.meadowy.org/meadow/
    Netinstall を利用する。
  2. Gauche をインストールする。
    http://practical-scheme.net/gauche/download-j.html
    Windows用バイナリインストーラを利用する。
  3. Meadow のインストールフォルダにある dot.emacs.ja を編集。以下の内容を追記する。
    追記したらファイル名を .emacs として保存
    ;;; Schemeの設定
    (setq process-coding-system-alist
          (cons '("gosh" utf-8 . utf-8) process-coding-system-alist))
    (setq scheme-program-name "gosh.exe -i")
    (autoload 'scheme-mode "cmuscheme" "Major mode for Scheme." t)
    (autoload 'run-scheme "cmuscheme" "Run an inferior Scheme process." t)
    
  4. Meadowを起動して、M-x run-scheme で gosh プロンプトが出てくればOK。

scheme-program-name の値は、Gauche をバイナリインストーラでインストールしていれば gosh.exe への Path は設定済のはずなので、ファイル名だけでいいはず。だめならフルパスを指定。

おまけ: emacs 操作メモ

  • M-x run-scheme : schme処理系開始
  • C-j : インデントつけて改行
  • C-/ : Undo
  • C-y : paste(yank)
  • C-@ : 範囲指定開始
  • M-w : コピー
  • C-x C-s : 保存
  • C-x C-w : 名前をつけて保存
  • C-c C-c : プロセスキル
  • C-c C-l : REPL処理系にロード

REPLのプロンプトでの操作

  • M-p : ヒストリ呼び出し(前)
  • M-n : ヒストリ呼び出し(次)

参考:





google-code-prettifyでシンタックスハイライト

chips-tips:

tumblrで使うコードハイライターをこっちに乗り換え。
テーマ(CSS)もあらかじめいくつか用意されてたりで気軽に使うならこれでいいかもしれないです。
そんなわけで軽く設置メモ。

<google-code-prettify>
上記サイトから必要なファイルをDL。
最小限分のprettify-small-1(日付)~でも使えるっぽいですが折角なんでフルの方をDLしました。
使うファイルはどっちも同じ。

Read More