Hatena::ブログ(Diary)

ものすごいハイウエスト日記 RSSフィード

 

2011-06-26

[]てっきり忘れてた てっきり忘れてたを含むブックマーク

先週ひなびたビジネスホテルでやったやつをこっちに貼るの忘れてたので再掲.

トラックバック - http://d.hatena.ne.jp/nbqx69/20110626

2011-06-14

[]impromptuでライブコーディング(余興レベル) その2 impromptuでライブコーディング(余興レベル) その2を含むブックマーク

フリーのAudioUnitのエフェクタをゲトして試したかったのでまたやってみた.アイデア自体は前回とおなじ(キーまでもおなじ)だけど,フレーズにあたるシーケンスのリストループするコールバック関数を生成するマクロを自前でかいたのでタイプ量がけっこう減りました.ライヴコーディングは仕込みがやっぱり大事

エフェクタは歪ませてからフィルタをかけてカットオフと混ぜ具合を変化させてます.けっこう音域的にもPCスピーカだとつらいかもしれません.

あ,あと画面の右下にエディタのステータスバーに出る情報をひっぱってきて表示させるようにしました.コードかいてるときはほとんどエディタをみてるのでなんの意味もありませんが…

トラックバック - http://d.hatena.ne.jp/nbqx69/20110614

2011-06-09

[]impromptuでライブコーディング(余興レベル) impromptuでライブコーディング(余興レベル)を含むブックマーク

twitterにも貼りましたがこっちにも貼っておきます

ちょこちょこといじったりはしてみたりしてたのですが試しにライブで書いてみました

つかってる音源は↓Magical 8bit Plugとimpromptu内蔵のサンプラーだけです

YMCK official web site

とりあえず気づいたことをいくつかかいておくと,シーケンスの組みたてがsexp(Impromptuはschemeベース)だと書きやすい反面,単純になりやすいのでmake-list, map, foldぽい畳みこみ系をうまくつかってシーケンスを動的に生成するとプログラマっぽいかなとおもったり,シーケンスのループがメインになるとシンタックスエラーのときのフォールバックをどうするかって対策をかんがえといたほうがいいかなっておもったりしました

外側の(OSCじゃない)連携とかOSCを介しての多言語連携(スパコっぽい使いかた)も一応アイデアがあるのでためしてみたいとおもってます

あ,あと今回のやつだとノイズ周波数スウィープをかけてメリハリつけてステップシーケンサ的なかちっとしたシーケンスにせず,わざとおかしな拍でループさせてポリリズムにしてるんですが,こういうアイデアはsexpでシーケンスループ方式ならではかもしれないですね

トラックバック - http://d.hatena.ne.jp/nbqx69/20110609

2011-05-12

[]CoffeeScriptはAdobeCSスクリプトエクリチュールとなりえるか CoffeeScriptはAdobeCSスクリプトのエクリチュールとなりえるかを含むブックマーク

まえまえから気になっていたのでInDesignをうごかすJavaScriptCoffeeScriptでかくとどんなかんじになるかためしてみた.

あくまでためしてみるだけだしInDesignでやるのはそんなにバッキバキなことではなくDTPでやることを自動的にやるかんじで.

こんなんです

InDesign CoffeeScripting from nbqx on Vimeo.

CoffeeScriptでかいたのはこんなかんじです.はてダだとまだシンタックスハイライトCoffeeScript無いっぽいのでpythonにしときます

##お約束
file = new File("/path/to/sample.indd")
app.open(file)
doc = app.activeDocument
tpl = doc.pages[0]

##このデータを…
data = [
  {name_jp:"唐 一郎", name_en:"Ichiro Kara", post:"会長"},
  {name_jp:"唐 二郎", name_en:"Jiro Kara", post:"副会長"},
  {name_jp:"唐 三郎", name_en:"Saburo Kara", post:"社長"},
  {name_jp:"唐 四郎", name_en:"Shiro Kara", post:"副社長"},
  {name_jp:"唐 五郎", name_en:"Goro Kara", post:"書記長"},
  {name_jp:"唐 六郎", name_en:"Rock'n'Roll Kara", post:"副書記長"},
  {name_jp:"唐 七郎", name_en:"Shichiro Kara", post:"代表取締役 専務"},
  {name_jp:"唐 八郎", name_en:"Hachiro Kara", post:"資材部 リーダー"}
]

##Arrayから条件にあうものをひとつピック
findOne = (a, fn) ->
  ret = []
  ary = if a instanceof Array then a else [a]
  for v in ary
    if fn(v) then ret.push(v)
  if ret.length is 0 then null else ret[0]

##引数のなにかをコピペ
copyAndPaste = (src) ->
  src.select()
  app.copy()
  app.paste()
  doc.selection[0]

##ラベルのついたテキストフレームを探して文字列をいれかえ
proc = (page,data) ->
  post = findOne page.allPageItems, ((o) -> if o.label is "post" then true else false)
  name_jp = findOne page.allPageItems, ((o) -> if o.label is "name_jp" then true else false)
  name_en = findOne page.allPageItems, ((o) -> if o.label is "name_en" then true else false)
  if post? then post.contents = data.post
  if name_jp? then name_jp.contents = data.name_jp
  if name_en? then name_en.contents = data.name_en

##データごとにページを追加しつつ…
for val in data
  p = doc.pages.add()
  for itm in tpl.allPageItems
    clone = copyAndPaste(itm)
    clone.move(p)
    clone.geometricBounds = itm.geometricBounds
  proc(p, val)

##X-1aなPDFを吐きだしてドキュメントを閉じる
pdf = new File(doc.fullName.toString().replace(/\.indd$/,".pdf"))
doc.exportFile(ExportFormat.PDF_TYPE,pdf,false,'[PDF/X-1a:2001 (日本)]')
doc.close(SaveOptions.NO)

alert('Done!')

でもってJavaScriptに吐きだしたやつ

(function() {
  var clone, copyAndPaste, data, doc, file, findOne, itm, p, pdf, proc, tpl, val, _i, _j, _len, _len2, _ref;
  file = new File("/path/to/sample.indd");
  app.open(file);
  doc = app.activeDocument;
  tpl = doc.pages[0];
  data = [
    {
      name_jp: "唐 一郎",
      name_en: "Ichiro Kara",
      post: "会長"
    }, {
      name_jp: "唐 二郎",
      name_en: "Jiro Kara",
      post: "副会長"
    }, {
      name_jp: "唐 三郎",
      name_en: "Saburo Kara",
      post: "社長"
    }, {
      name_jp: "唐 四郎",
      name_en: "Shiro Kara",
      post: "副社長"
    }, {
      name_jp: "唐 五郎",
      name_en: "Goro Kara",
      post: "書記長"
    }, {
      name_jp: "唐 六郎",
      name_en: "Rock'n'Roll Kara",
      post: "副書記長"
    }, {
      name_jp: "唐 七郎",
      name_en: "Shichiro Kara",
      post: "代表取締役 専務"
    }, {
      name_jp: "唐 八郎",
      name_en: "Hachiro Kara",
      post: "資材部 リーダー"
    }
  ];
  findOne = function(a, fn) {
    var ary, ret, v, _i, _len;
    ret = [];
    ary = a instanceof Array ? a : [a];
    for (_i = 0, _len = ary.length; _i < _len; _i++) {
      v = ary[_i];
      if (fn(v)) {
        ret.push(v);
      }
    }
    if (ret.length === 0) {
      return null;
    } else {
      return ret[0];
    }
  };
  copyAndPaste = function(src) {
    src.select();
    app.copy();
    app.paste();
    return doc.selection[0];
  };
  proc = function(page, data) {
    var name_en, name_jp, post;
    post = findOne(page.allPageItems, (function(o) {
      if (o.label === "post") {
        return true;
      } else {
        return false;
      }
    }));
    name_jp = findOne(page.allPageItems, (function(o) {
      if (o.label === "name_jp") {
        return true;
      } else {
        return false;
      }
    }));
    name_en = findOne(page.allPageItems, (function(o) {
      if (o.label === "name_en") {
        return true;
      } else {
        return false;
      }
    }));
    if (post != null) {
      post.contents = data.post;
    }
    if (name_jp != null) {
      name_jp.contents = data.name_jp;
    }
    if (name_en != null) {
      return name_en.contents = data.name_en;
    }
  };
  for (_i = 0, _len = data.length; _i < _len; _i++) {
    val = data[_i];
    p = doc.pages.add();
    _ref = tpl.allPageItems;
    for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
      itm = _ref[_j];
      clone = copyAndPaste(itm);
      clone.move(p);
      clone.geometricBounds = itm.geometricBounds;
    }
    proc(p, val);
  }
  pdf = new File(doc.fullName.toString().replace(/\.indd$/, ".pdf"));
  doc.exportFile(ExportFormat.PDF_TYPE, pdf, false, '[PDF/X-1a:2001 (日本)]');
  doc.close(SaveOptions.NO);
  alert('Done!');
}).call(this);

まだCoffeeScriptだとこんなべんりにできるよーとか把握してなくてアレなのですが,とかくループネストが凶暴な牙を剥きがちなCS系のJavaScriptループがかなりスッキリするし,あと今回はつかってないんだけどHash(というかオブジェクトというかjsonというか)もforでkeyとvalueがひっぱってこれるのでスッキリするんじゃないかとおもいます.それと何気にelvis演算子が小気味いいとおもいました,これもけっこうちゃんとチェックするのメンドーだし.ただじぶんの場合JavaScript書くとき三項演算子をけっこうつかうのでそれが"if xxx then yyy else zzz"になるのはちょっとなーとおもいました.そのためだけに"`"つかって生JSいれるのもアレだし…

しかしながら,まだがっつりつかっていこうってかんじではないけど可能性としてはありかもなとおもいました.

つかJavaScriptエクリチュールとしてちょーおもろい

トラックバック - http://d.hatena.ne.jp/nbqx69/20110512

2011-05-11 あまりにかかなすぎ

[]Groovy+JsynでDTMF発信する Groovy+JsynでDTMF発信するを含むブックマーク

気がついたら数ヶ月もかいてませんでした.

なにもしていないってわけでもなくて,さいきんはtwittergistvimeoリンクはってそれでおわりってパターンばかり.

ウェブログ離れってのもあながち無いってわけではないなと実感するこのごろ,みなさんいかがお過しでしょうか,どうも.おれです.

というわけで昨晩思いつきでやってみたDTMF(Dual Tone Multi Freqency)をGroovyとJsynでというお話

DTMFてのはデュアルにトーンでマルチフリーケンシーでというもので,もっとカンタンにいえば電話のプッシュ音のことです.つまり電話のプッシュ音はデュアルなトーンをマルチフリーケンシーになっている,もっとカンタンにいえば2つの周波数正弦波を組み合わせて電話のプッシュ音ができてるっていうことです.つまり電話のプッシュ音は2つの周波数のSineWaveってことですね.もっとカンタンにいうとDTMFっていうことなんですね.

その2つの正弦波の組み合わせで0から9とシャープ記号,ポートピア連続殺人事件でおなじみのコメ記号,AからDまでのアルファベット表現するのがDTMFです.あんまり詳しいはなしをすると90年代中頃までぐらいのラジオライフみたいな話になってしまうのでググってみたほうがいいと思います.というかじぶんもあまり詳しいはなしはできません.

DTMF with Groovy from nbqx on Vimeo.

とりあえず117にかけてますが失敗してます.ちなみに何度かテストしてるときに1度だけコールすることができました.

twitterでmiura_offさんともお話したのですが,以前「探偵ナイトスクープ」で合唱団員2人でDTMF発信するのをやっててけっこう大変ぽいかんじだった覚えがあります.そんなカンタンにはできないのかもしれません.

以下Groovyコードです.わかりやすさ重視のため,おかしなことはしていません.

せめて数字・記号・アルファベットから2つの周波数をひっぱるとこあたりはクロージャメモ化してもいいかもです.連続でDTMF発信したりとてつもなく長い電話番号に発信しない限りは必要ないんじゃと個人的には思いますが…

import com.softsynth.jsyn.*

//groovy script for phone call
class DualToneMultiFrequency{
	def num
	def buf
	SineOscillator high
	SineOscillator low
	AddUnit mixer
	LineOut out

	public DualToneMultiFrequency(String str){
		Synth.startEngine(0)
		num = str.toList()

		high = new SineOscillator()
		low = new SineOscillator()
		mixer = new AddUnit()
		out = new LineOut()

		buf = num.collect{x-> dtmfMatrix[x]}
	}

	def exec = {
		high.output.connect(0,mixer.inputA,0)
		low.output.connect(mixer.inputB)

		mixer.output.connect(0,out.input,0)
		mixer.output.connect(0,out.input,1)

		high.start()
		low.start()
		mixer.start()

		buf.each{
			dial(it)
		}

		out.stop()
		Synth.stopEngine()
	}

	def dial = {x->
		high.with{
			frequency.set(x.higher)
			amplitude.set(0.5)
		}
		low.with{
			frequency.set(x.lower)
			amplitude.set(0.5)
		}

		out.start()
		Synth.sleepForTicks(80)

		out.stop()
		Synth.sleepForTicks(60)
	}

	def dtmfMatrix = [
		"1":[higher:1209, lower:697],
		"2":[higher:1336, lower:697],
		"3":[higher:1477, lower:697],
		"4":[higher:1209, lower:770],
		"5":[higher:1336, lower:770],
		"6":[higher:1477, lower:770],
		"7":[higher:1209, lower:852],
		"8":[higher:1336, lower:852],
		"9":[higher:1477, lower:852],
		"*":[higher:1209, lower:941],
		"0":[higher:1336, lower:941],
		"#":[higher:1477, lower:941],
		"A":[higher:1633, lower:697],
		"B":[higher:1633, lower:770],
		"C":[higher:1633, lower:852],
		"D":[higher:1633, lower:941]
	]

}

def dtmf = new DualToneMultiFrequency("117")
dtmf.exec()
トラックバック - http://d.hatena.ne.jp/nbqx69/20110511