てっきり忘れてた
先週ひなびたビジネスホテルでやったやつをこっちに貼るの忘れてたので再掲.
impromptuでライブコーディング(余興レベル) その2
フリーのAudioUnitのエフェクタをゲトして試したかったのでまたやってみた.アイデア自体は前回とおなじ(キーまでもおなじ)だけど,フレーズにあたるシーケンスのリストをループするコールバック関数を生成するマクロを自前でかいたのでタイプ量がけっこう減りました.ライヴコーディングは仕込みがやっぱり大事.
エフェクタは歪ませてからフィルタをかけてカットオフと混ぜ具合を変化させてます.けっこう音域的にもPCのスピーカだとつらいかもしれません.
あ,あと画面の右下にエディタのステータスバーに出る情報をひっぱってきて表示させるようにしました.コードかいてるときはほとんどエディタをみてるのでなんの意味もありませんが…
impromptuでライブコーディング(余興レベル)
twitterにも貼りましたがこっちにも貼っておきます
ちょこちょこといじったりはしてみたりしてたのですが試しにライブで書いてみました
つかってる音源は↓Magical 8bit Plugとimpromptu内蔵のサンプラーだけです
とりあえず気づいたことをいくつかかいておくと,シーケンスの組みたてがsexp(Impromptuはschemeがベース)だと書きやすい反面,単純になりやすいのでmake-list, map, foldぽい畳みこみ系をうまくつかってシーケンスを動的に生成するとプログラマっぽいかなとおもったり,シーケンスのループがメインになるとシンタックスエラーのときのフォールバックをどうするかって対策をかんがえといたほうがいいかなっておもったりしました
外側の(OSCじゃない)連携とかOSCを介しての多言語連携(スパコっぽい使いかた)も一応アイデアがあるのでためしてみたいとおもってます
あ,あと今回のやつだとノイズに周波数スウィープをかけてメリハリつけてステップシーケンサ的なかちっとしたシーケンスにせず,わざとおかしな拍でループさせてポリリズムにしてるんですが,こういうアイデアはsexpでシーケンスループ方式ならではかもしれないですね
CoffeeScriptはAdobeCSスクリプトのエクリチュールとなりえるか
まえまえから気になっていたのでInDesignをうごかすJavaScriptをCoffeeScriptでかくとどんなかんじになるかためしてみた.
あくまでためしてみるだけだしInDesignでやるのはそんなにバッキバキなことではなくDTPでやることを自動的にやるかんじで.
こんなんです
- マスターページに名刺っぽい台紙をつくっておいたinddファイルを開く(1ページ目はテンプレート)
- スクリプトのなかにオブジェクトをもっておいて,ひとつのデータにつき1ページ目のテンプレートを複製していく
- 各ページにあるテキストフレームからラベルのついたものをひっぱりだしてテキストをいれかえる
- X-1aなPDFを書きだしてinddファイルをとじる
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のエクリチュールとしてちょーおもろい
Groovy+JsynでDTMF発信する
気がついたら数ヶ月もかいてませんでした.
なにもしていないってわけでもなくて,さいきんはtwitterにgistかvimeoのリンクはってそれでおわりってパターンばかり.
ウェブログ離れってのもあながち無いってわけではないなと実感するこのごろ,みなさんいかがお過しでしょうか,どうも.おれです.
というわけで昨晩思いつきでやってみた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発信するのをやっててけっこう大変ぽいかんじだった覚えがあります.そんなカンタンにはできないのかもしれません.
http://twitter.com/miura_off/status/68004528225665024:twitter
http://twitter.com/nbqx/status/68110846202621952:twitter
http://twitter.com/miura_off/status/68116821663952897:twitter
以下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()
スクショ無限ループ
よくわからないのですが,こういう「無限につづいていくもの」って正月っぽいんじゃないでしょうか.
たぶんおせち料理にもこういう由来をもつものもありそうですが.
テキトーいってます,すみません.
スクリプトを2つうごかしてグリグリうごかしてみた
ScreeeenShoooooot from nbqx on Vimeo.
import processing.core.* import javax.swing.JFrame import java.awt.* import java.awt.image.* import java.awt.Robot class App extends PApplet{ Toolkit toolkit Robot robot PImage img void setup(){ //size(screen.width/2 as int, screen.height/2 as int) size(screen.width as int, screen.height as int) colorMode(RGB) toolkit = Toolkit.getDefaultToolkit() robot = new Robot() } void draw(){ BufferedImage bufImg = robot.createScreenCapture(new Rectangle(toolkit.getScreenSize())) img = new PImage(bufImg) image(img,0,0) } } app = new App() app.init() jframe = new JFrame(title:"ScrreeenShoooooot",resizable:true).with{ add(app) pack() defaultCloseOperation = JFrame.EXIT_ON_CLOSE resizable = true visible = true }
javascript関連
ブラウザとかInDesignとかIllustratorでのExtendScriptはいうにおよばず,Titanium Mobileだったりnode.jsだったりcouchDBだったり.なにからなにまでJavascript書きまくった気がします.今年は夜のライブコーディングがほとんどできなかったし,コーディング量としてはいちばんJavascriptを書いたかもしれない.
ExtendScriptは実務にすぐ使えるよみたいなものではなくて,メタプログラミング向けの部品をつくってた.DIっぽいものとかモジュラーなライブラリだったり.メタっぽい話だとこういうとこに書いてもなーっていうふうにおもったりして書いてない部品のはなしとかけっこうあるんですが.もうすこし具体的にして実用的につかえるみたいなものができてくれば来年あたり書いていきたいなとおもいます.
node.jsではTitanium Mobileのiosアプリをビルドをするサーバを書いたり,SimpleNoteっていうwebサービスのクライアント(まだ汚ないけど)を書いたりしておもしろかった.これとかはじぶんのgistにおきました.
特にTitanium Mobileのビルドするやつはvimからcurl動かしてってやつなんだけど,perlで同じうごきをされてる方もいらっしゃいましたが,実際はビルドするだけじゃなくてその下準備なんかもイベント駆動で処理したり.
node.jsはじぶんでもつくってみたいものもあるので,来年はCモジュールに着手するよていです.つかもうすでに手をつけはじめてます.
-
- -
というわけで思いつく限りのハイウエスト向けの今年の話でした.よいお年をお向かえください.