ラベル tips の投稿を表示しています。 すべての投稿を表示
ラベル tips の投稿を表示しています。 すべての投稿を表示

日曜日, 6月 05, 2016

Processingで画像を読み込みたいけどファイルの数や名前が分からない場合

課題

Processingで大量の画像を読み込んで処理したかったのだけど、標準のloadImage()を使おうとするとファイル数やファイル名が予め分かっていないといけない。つまり画像ファイルを追加したり削除したりすると、それに合わせてコードも修正しなければならない訳で、保守性も効率も悪い。

解決法

JavaにFilenameFilterというインターフェースがあるので、新しくクラスを作ってacceptメソッドをオーバーライドする。

import java.io.File;
import java.io.FilenameFilter;

public class PngFileFilter implements FilenameFilter {
  @Override
  public boolean accept(File directory, String fileName) {
    if(fileName.endsWith(".png")) {
      return true;
    }
    return false;
  }
}

PngFileFilterクラスのインスタンスを作り、こんな感じでFileクラスのlistFilesメソッドに渡すと、".png"で終わるファイルが配列として返ってくる。ちなみにdataPath("")という関数を使うとdataフォルダまでのパスが取得できる。空の文字列を渡しているが、フォルダがある場合はその名前を指定できる。リファレンスに載っていないのである日突然なくなる可能性はある。

File[] imageFiles;
PngFileFilter filter;
void setup() {
  size(800, 800);
  filter = new PngFileFilter();
  imageFiles = new File(dataPath("")).listFiles(filter);
  for(File file: imageFiles) {
    println(file.getName());
  }
}

RubyとかPythonだと特定のフォルダ以下のアセットを特定の拡張子で読み込むのが簡単なので、ああいう感じの書き方にできるとより便利。他の言語や環境から学ぶことは沢山ある。

日曜日, 9月 21, 2014

Processingでアプリケーションを作る際に知っておくと便利なコード

ホームディレクトリのパスを取得

Processingでアプリケーションとして書き出す際に、リソースを後で差し替えたかったり、dataフォルダ以外に置きたい場合があります。ProcessingというよりはJavaのAPIですが、
System.getProperty("user.home")
でユーザのホームディレクトリの絶対パスが取得できます。例えば、
import java.io.*;
File movieFolder = new File(System.getProperty("user.home") + "/movies");
File[] movieFiles = movieFolder.listFiles(getFileExtensionFilter(".mp4"));

とすると、ホームディレクトリ以下に置いたmoviesフォルダ内にある.mp4ファイルを取得できます。.mp4を他の拡張子に変えれば他の拡張子も取得可能です。

スライドショー機能で使った画像のフェードイン・アウトのサンプルコード

地味にProcessingで画像がフェードイン・アウトする処理を書いたのは初めてでした。tint()を使うとできます。
fadeInOut.pde

これらは現在『六甲ミーツ・アート 芸術散歩』で展示中のNadegata Instant Partyの作品の自動撮影システムに活かされています。撮影された画像は自動でTumblrにアップロードされるのですが、開発の期間が限られていたため、IFTTTのDropbox連携を使いました。
PHOTO SPOT PARTY

土曜日, 10月 02, 2010

ArrayListについて認識を改めたところ

以前の投稿(build ribbons)で、
for文のところを単にかっこいい書き方としか認識してなかったんですけど、
配列の長さがループの途中で変わるので、ああいう風にしておかないとremoveで取り除かれた分の添字が詰まった結果、参照されないオブジェクトがでてきてしまってちらつきが起こってしまいます。

こういう場合。
試しにdraw()内のfor文の初期化式をint i=0、継続条件式をi<ripples.size()、再初期化式をi++にしてみると分かります。
リファレンスにも似たような例が書いてあって、Examples>Topics>Advanced Data>ArrayListClassでも確認できます。
[Ripple.pde]
class Ripple {
float x, y, w, speed;
float age;
int intensity;
color c;
float a;
boolean finished;

Ripple(float x, float y, int intensity, color c, float speed) {
this.x = x;
this.y = y;
this.intensity = intensity;
this.c = c;
this.speed = speed;
this.age = 0;
this.a = 255-255*(age-speed)/intensity;
this.finished = false;
}

void display() {
age += speed;
a = 255-255*(age-speed)/intensity;
if(a<=5) {
finished = true;
}
stroke(c, a);
ellipse(x, y, age, age);
}

boolean finished() {
return finished;
}
}

[drawRipple.pde]
Ripple r;
ArrayList ripples;
void setup() {
size(400, 400);
background(255);
noFill();
smooth();
ripples = new ArrayList();
for(int i=0; i < 100; i++) {
ripples.add(new Ripple(random(width), random(height), (int)random(20, 80), color(0), random(0.1, 0.4)));
}
}

void draw() {
background(255);
for (int i = ripples.size()-1; i >= 0; i--) {
Ripple ripple = (Ripple)ripples.get(i);
ripple.display();
if(ripple.finished()) {
ripples.remove(ripple);
}
}
}

金曜日, 2月 01, 2008

MAX_FLOAT, MIN_FLOAT

visualizing data読み始めて、知った。
最小値とか最大値を比べて取得する場合、初期値を代入する時に

float dataMax = MIN_FLOAT;
float dataMin = MAX_FLOAT;

としておく。
読んで字のごとくMIN_FLOATはfloatで一番小さい値で、MAX_FLOATはfloatで一番大きい値。
どんな数値もこれより小さくて大きい。

sonicodeでは文字をビットマップにして黒いところに順番に番号つけて、縦のセルで大きさを比べて最大値と最小値を出してるんだけど、最大値を入れるための変数の初期値を0にしてた。これだと負の値がきたときに動かない。
設計上負の値がくることはないからいいや、と思ってたけど、気持ち悪かったんだよね。
MIN_INT, MAX_INTもある。

0126から追加されたみたい。

金曜日, 1月 04, 2008

recursion

it's hoba
シンプルなコードで、視覚的に強い。

血が滴るみたいなやつ。
it's hoba: Processing 13

再帰を使って書き直してみた。

//based on hoba's code(http://hobagoogle.blogspot.com/2007/12/processing-13.html)
//rewrite by using recursion
void setup() {
size(800, 450);
background(152);
noStroke();
smooth();
colorMode(HSB);
}

float e, r, var, posx, posy, a, dex, lengh, bri;
int cnt;

void draw() {
}

void mousePressed() {
e = HALF_PI/180*30;
a = 1-sin(e);
r = random(30, 150);
var = random(0.6, 0.9);
dex = random(-0.15, 0.15);
lengh = random(0.8, 1.2);
bri = random(0, 1);
posx = mouseX;
posy = mouseY;
cnt = int(random(30, 200));
fill(2, 247, 80+50*bri);
ellipse(posx, posy+r*HALF_PI/180*var, r/20+r, r/20+r);
blood(posx, posy, r, var, dex, lengh, bri, cnt);
}

void blood(float posxU, float posyU, float rU, float varU,
float dexU, float lenghU, float briU, int cnt) {
fill(2, 247, 80+50*briU, 100-100*a);
ellipse(posxU+dexU*rU, posyU+rU*e*varU, rU/20+rU*a*a, rU/20+rU*a*a);
e += HALF_PI/180;
a = 1-sin(e);
if(cnt>0 && e<=HALF_PI*lenghU) {
blood(posx, posy, r, var, dex, lengh, bri, cnt-1);
}
}

void keyPressed() {
if (key == 'r' || key == 'R') {
background(152);
}
}

木曜日, 12月 20, 2007

Reading newsfeeds

GainerでおなじみアカデミーDSPの小林さんがnodeboxワークショップやってる。
DSP

天気情報のrssを取得して表示。webライブラリを使う。
NodeBox | Web

text()メソッドに渡す際にstr()メソッドを使うんだけど、utf-8にdecodeしないとエラーになる。デフォルトのエンコーディングがutf-8になってないから?
3. 形式ばらない Python の紹介

文字コードは常に悩みの種。いつも何となく解決してるので、ちゃんと理解せねばと思う。


web = ximport("web")
fontsize(10)
news = web.newsfeed.parse("http://weather.livedoor.com/forecast/rss/21/40.xml")
y=0
xoff=10
yoff=10
for i in news.items:
s = str(i.description).decode('utf-8')
text(s, xoff, y*30+yoff)
y+=1


同じことをprocessngでやるとこうかな。もっと泥臭い感じ。
関係ないけど文字表示する場合PFont.list()で一覧とって配列の一番最初のを指定してあげればいちいちメニューからCreate Font...しなくて済む。


import processing.xml.*;
XMLElement xml;
XMLElement[] siteData;
xml = new XMLElement(this, "http://weather.livedoor.com/forecast/rss/21/40.xml");
XMLElement site = xml.getChild(0);
siteData = site.getChildren();
PFont font;
String[] fontlist = PFont.list();
font = createFont(fontlist[0], 10);
textFont(font);
size(400, 400);
int y = 0;
for(int i=0;i<siteData.length;i++) {
if(siteData[i].getName().equals("item")) {
XMLElement[] items = siteData[i].getChildren();
for(int j=0;j<items.length;j++) {
if(items[j].getName().equals("description")) {
text(items[j].getContent(), 10, y*30);
println(items[j].getContent());
y++;
}
}
}
}

木曜日, 10月 18, 2007

20071017

画像から波形をpysndobjでできるようにした。

画像を扱うためのライブラリであるPython Image Libraryを導入するのに手間取ってしまった。OSXの場合、ソースからビルドしなければならない。諸悪の根源はPILというか、デコーダのlibjpegなんだけど。
PIL(Python Image Library)の導入 — JZUG
libjpeg.dylib のコンパイル方法 - Cube の日記
PIL のエラー解決編 - mitszoの日記
【コラム】OS X ハッキング! (42) OS XでGIMPを使おう! part4 | パソコン | マイコミジャーナル
あと海外でインストーラ作ってくれてた人もいたな。

この辺全部試して、
jpeg-6bフォルダ内で./configureとかmake installとかひたすら打ち込み、文字列をずらーっと眺める。

Imaging-1.1.6フォルダ内でsetup.py buildしたらちゃんと
--- JPEG support ok
が出るにも関わらず、pythonを起動してImageをインポート、jpegファイルを読み込もうとすると、
IOError: decoder jpeg not available
となる。

で、エラーログで検索したら、setup.pyを2回以上行う場合はbuildフォルダを消しておく必要があることが判明。無事解決。とは言え、どれが決め手だったのかは不明...。
decoder jpeg not available - あるシステム管理者の日常

sudo setup.py install

PILさえ入れてしまえば画像表示は超簡単で、

import Image
Image.open("kaho001.jpg").show()

だもんね。
P型フーリエ記述子とかいうのを試してみたいんだけど、できるかしら。僕に。

本当、こんなにわかってないものをよく毎日使ってるなぁと思った。ちょっと普段と違うことしようとすると途端に困ったことになる。

木曜日, 8月 02, 2007

average.js


Max/MSPで受け取る値の平均をとるjavascript書きました。Maxでのjavascriptって何か慣れなくて、すぐ忘れてしまう。できたと思ったら思いっきりgainerの公式サイトにありました。今まで何回もノイズだったり急激な数値の変化に悩まされてきたもんなー。
GAINER.cc | Cookbook / 移動平均法によるスムージング

これよりかはちょっと柔軟になってて、setメッセージで配列の長さを可変にしてあります。デフォルトは100。resetを送ると配列の中身を全て0にします。

こういうインタラクティブインスタレーションなどでよく使うメソッドはもっと共有されるべきだと思う。
averagejs.zip

土曜日, 7月 07, 2007

note20070707

Max/MSP
ubumenuでQuickTimeMovieファイルだけを表示したい場合はInspectorでFiltered TypesにMooVと書く。

css
共通スタイル、各ページ毎のスタイルでファイルを分ける。
共通のとこで全称セレクタ使ってmarginとpaddingを0にしておくと便利。

html
見出し要素は順番を守る。文字の大きさではなく、構造。
定義リストが便利。会社概要とかはこれで書く。

javascript
MDC
メインページ - MDC
brazilさんに教えてもらったbookmarkletのわかりやすい解説
Bookmarklets - Browser Power

misc
Arkitip™ | Intelligence
複数の色んな肩書きの人達が記事や写真をアップしてる。サイトが綺麗。
Magazineのissue0032でexpelimental jetset特集。高かったけど良かった。

プロサッカー選手はスルーパスを受ける時、観客の目線が自分の目線のように感じられて、動くべき場所とタイミングがわかるらしい。

ふんわり何とかが食べたい。

月曜日, 7月 02, 2007

bbbbig!

画像のブックマーク+おすすめサイトffffound!の画像表示がちっこくなってしまった。元画像は保存されてて、ファイル名の_mを取れば表示できるということで、bookmarkletの勉強がてらやってみた。
bbbbig!てやつです。
letsbookmark

最初はsubstring(0,ファイル名-6)で_m.jpgの部分(後ろから6文字)を取って+".jpg"でまた拡張子つけたやつを表示させてたんだけど、これだとあまりに頭が悪い。関係ないのも読まれるし他の拡張子表示できないし。
で、youpy(ぴよよぴぴよよぴ)さんのGreaseMonkeyスクリプトを参考にmatch('_m')で該当する画像だけを取得して、その後split('_m').join('')して_mを取り除いてる。なるほどー。

やっぱ画像でかいと印象が全然違う。音も然り。

土曜日, 6月 16, 2007

program switcher

processingで例えばvjする時とか、どうやって切り換えするかなって疑問は前からあって、やっとその答えが出た。
abstractmachine >> Polymorphism
abstractmachine >> abstract classes

ポリモーフィズムね、抽象クラスね。やったやった。でも使い方全然わかってなかった。本当こういうテクニックって、できる人にとっては言うまでもないことで、僕くらいの知識だと思いつかないからなかなか共有されないんだよね。ここで駄目なやり方として紹介されてるswitch文で書いてた。

Polymorphismのはdouglasのページのをそのまま実行すればいいとして、abstract classesでのやつをやってみた。これでいいのかな。確かに変数のことで悩まなくて済むしコードも綺麗だ。Head First Javaで勉強し直そう...。


abstract class Animation {
void setup() {
background(255);
}

abstract void draw();
}

class Opening extends Animation {
int i=0;
void draw() {
background(255);
if(i>width) {
i=0;
}
line(i, 0, i, height);
i++;
}
}

class Middle extends Animation {
int i=0;
void draw() {
background(255);
if(i>height) {
i=0;
}
line(0, i, width, i);
i++;
}
}

class Ending extends Animation {
void draw() {
background(random(255));
}
}

Animation myAnimation;
void setup() {
myAnimation = new Opening();
}

void draw() {
myAnimation.draw();
}

void keyPressed() {
switch(key) {
case 'a':
myAnimation = new Opening();
break;
case 'b':
myAnimation = new Middle();
break;
case 'c':
myAnimation = new Ending();
break;
}
}

木曜日, 6月 14, 2007

gainer digital in


gainerでdigital inからmaxに値を送るとこで一瞬はまったので書いとく。d.inからはmetroで指定した時間間隔で毎回0なり1を出力し続けてる。なのでそのままだとsfplay~がちゃんと使えない。toggleの見た目的にはずっと1になってていけてそうだが、実際は毎回頭出しされてることになる。なので、togedgeを使って0から1、もしくは1から0になった時だけメッセージを送るようにしてあげればよい。togedgeはインタラクティブ系ではすげーお世話になるので覚えておくと便利。画像はd.inからのメッセージが1の場合と0の場合で別の音源を鳴らすデモのために作ったパッチの一部。
record~オブジェクトで1の間だけ録音したい場合もこれで対応できる。これやっとかないと一瞬録音されてまた次の1が来た時にbuffer~の内容が書き換えられてしまう。append 1メッセージを送れば一応togedge使わなくても回避できるけど、挙動が違ってくるので目的に応じて変えるべき。

木曜日, 6月 07, 2007

sketch20070607

NodeBox、まだ何するかは決めてないけど何となく役に立ちそうと思ったのは、当たり前かもしれないけど普通にpythonが動くこと。「初めてのPython」読みながらちょっと試す。

urllibモジュール使ったりすれば簡単にネットからデータを取得できる。google.co.jpのトップページ。wordscountのとこで適当な言葉を指定して、使われてる回数分四角を表示する。

from urllib import *
page = urlopen('http://www.google.co.jp')
data = page.read()
size(400, 800)
wordscount = data.count('google')
for i in range(wordscount):
rect(i*15, 0, 10, 10)
fontsize(9)
text(data, 0, 10, WIDTH)
page.close()

こういうのをもっと洗練させていけば色々面白い視覚化ができそう。pythonとかネットワークの勉強にもなるし。pdfとquicktimeムービーが書き出せるのもいい。mail用のモジュールもある訳だし、スパムメールの視覚化とか。こういうの。もうちょいポップなやつ作りたい。

他パラパラとめくりながら試してたやつ。

word = 'xo'
z = eval("word*10")
text(z, 0, 13, None)

とか。便利。

import os
print os.listdir(os.getcwd())

とかでカレントディレクトリにあるディレクトリのリスト出したり。os.mkdir('filename')でディレクトリ作ったりもできる。まだコンソールに出してるだけだけど、グラフィックにすぐ反映させられるはずで、それはやっぱ面白い。

こういうのは結構無駄っぽいけど、無駄な分あんまり人がやらない感じで、それによってあんまり見たことないようなグラフィックなりサウンドが生成できたらいいなぁと思う。同時にアルゴリズムとかコンピュータのコアな部分の勉強にもなりつつ。

あと、processingだとこれは多分こんなに簡単にはできないってのは、NodeBoxのfiles()メソッド使ってマウスダウンしてる間指定したフォルダ(絶対パス)内のjpgファイルをランダム表示。結構脳にくる。

size(600, 600)
speed(30)
def setup():
global f
f = files("/Users/poki_j/Documents/downloads/clipping/*.jpg")

def draw():
global f
if mousedown:
image(choice(f), 0, 0)

processingだと基本的にはスケッチフォルダ内にdataってフォルダ作ってそこに画像ファイル入れて読み込むし、読み込むファイルも拡張子だけの指定な場合、多分javaから何かしらをimportしないといけなさそう。そういう方法も知っといた方がいいような気はするけど。

金曜日, 6月 01, 2007

movie like effect


これみてやってみた。要は彩度下げて明るさ落としてコントラスト上げてどっかに焦点決めてそれ以外をぼかして暗くしていい感じにノイズを入れれば良い。今まで全然レタッチってやってこなかったけどこんなに質感て変わるものなのかと思った。次はミニチュアのやつマスターしよ。

元画像。ちょっと前東京行った時に何も考えないでファインダーもモニタも見ないで撮った。

火曜日, 5月 29, 2007

libJMyron.jnilib compiled for intel macs

jmyronをintel macで動かす場合はここからdownloadしたlibJMyron.jnilibに入れ替える(thanks kevin!)。

火曜日, 5月 22, 2007

prosvg

tex/tspで出した音の波形を印刷したいんだけど、解像度とか編集のしやすさのことも考えるとillustratorのパスで扱えるようにしたい。てな訳でproSVGを使ってみた。

素直にここのを落としてlibrariesに入れてexample実行すればいけるかと思いきや、

Exception in thread "Thread-2" java.lang.NoClassDefFoundError:

で、forum見たら同じエラーで困ってる同じく初心者でよくわかりませーんという人がいて、どうやらエラーの内容はSVGOut.javaとSVGGraphics.javaがコンパイルされてない(.classファイルがない)ってことなんだけど、僕も彼もコンパイルの方法がわかんない。terminalから素直にjavacしただけでは駄目みたい。

で、スレッドの2ページ目florian jenettって人が代わりにコンパイルしてくれてます。日本では神と呼ばれる行為ですね。僕の環境は0124ですが、問題なく動いてます。thanks florian!

音響界のhello worldことサインウェーブ。100*100で書き出して適当にillustrator上で拡大。最高。頂点結ぶのがスマートっぽいけど、とりあえずこれで。.tifファイルも書き出しとくとプレビューできていい感じ。



import prosvg.*;
void setup(){
size(100,100,"prosvg.SVGOut");
strokeCap(ROUND);
stroke(0,100);
smooth();
background(255);
strokeWeight(0.5);
}

void draw(){
float a = 0.0;
float inc = TWO_PI/100.0;

for(int i=0; i<100; i++) {
line(i, 50, i, 50+sin(a)*40.0);
a = a + inc;
}
saveFrame("testFlowers-####.tif");
saveFrame("testFlowers-####.svg");
noLoop();
}

水曜日, 4月 11, 2007

printing

jamesの手伝いで、大判プリント作業。
変な線が入ってしまったり、よくみるとジャギーが入ってたりとなかなか難しい。色の確認しようにも普段の作業場と大判プリントができる部屋ではモニタの色も違うし。変な線はプリンタの双方向印刷のチェックを外して単方向印刷にすればよかったのだけれど、綺麗な印刷を実現するにはソフト側で色々調整するより紙とプリンタの距離とかそういうとこがポイントになってくるそうだ。音もそうだけど、最終出力がアナログになると途端に理論だけでは説明のつかない世界に。
謎の汚れがついちゃったりね。大変。

木曜日, 3月 29, 2007

max and applescript



赤松先生の記事を読んでもしやと思ってやってみた、mxjでapplescript。前にiTunesを制御してたので、unixからapplescriptを呼び出すosascriptが動くことはわかってた。単純にStringを引数にしたメソッドを作って、Processに渡してるだけ。スクリプトとかプログラムを日常的に使う感覚がようやくわかったきた。書き捨てってやつ。ちょっとした頭の体操。メソッドの名前とか迷うな...。max側で使う際に良さげな感じにしました。MaxとAppleSCriptでmasc。興味ある方はmxj quickieとかでコンパイルして試してみてください。

[source code]

土曜日, 2月 24, 2007

actionscript

actionscript関係で、仕事のオファーが来て、受けないつもりだけど、リサーチ。ちなみにflashは全然使えません。前から気になってて、古堅さんも「これでもうjava何年も触ってない」ってほど使ってる、MTASCを入れてみた。んだけど、どうやら世間はAction Script 3で、Flex 2っていう開発環境がAdobeから無料で配布されてるのでそっちも。

MTASCインストールするのに、環境変数とか何とか勉強になった。finderから起動するアプリに環境変数を指定するには
~/.MacOSX/environment.plist
てファイルを作って(.MacOSXってフォルダも作って)、XML形式で書くと。
で、僕この方法よく分からず、かつeclipseの起動ができなくなったので、やめました。

とった方法は.bash_profile(ログインした時に実行されるファイル)のPATH=""の中を編集。
/展開した場所/mtasc-1.12-osx
というのを:でつなげて入れる。
一旦ターミナルをログアウトして、再びログイン、

mtasc

と入力して

Motion-Twin ActionScript2 Compiler 1.12 - (c)2004-2005 Motion-Twin
Usage : mtasc.exe [options]
Options :
 ー以下省略ー

と出ればよい。

この辺が勉強になりました。検索ですぐ見つかるけど。
ActionScript 2とFlash OOPのすすめ

Flex 2 SDKはAdobeのメンバーシップに登録して、zipファイルをダウンロード。展開して、適当な場所に置いて、player/debugの中のInstall Flash Player 9 UB.dmgを実行。

MTASCでやったように.bash_profileに
/展開した場所/flex_sdk_2/bin
を追加して、ログアウト。

mxmlc

というコマンドを実行して

Loading configuration file /Users/iamas/dev/flex_sdk_2/frameworks/flex-config.xml
Error: a target file must be specified

Use 'mxmlc -help' for information about using the command line.

と出れば成功。sampleフォルダの中のbuild-samples.shはすげー時間かかった。

ここ見て恒例のhello world!
ActionScript3.0メモ

javaに似てる。

色んな言語の基本的なとこばっか触って喜んでるんだけど、そろそろそういう環境おたくもやめないとなー。結局それで何するか、だ。やっぱり。というか、やりたいことがあって、必要条件として言語の習得があったはずなのに、いつの間にか言語の習得それ自体が楽しくなっちゃって、必ずしも悪いことでもないと思うんだけど、もっとアイディアありきで考えたいなと、最近は思う。
Scriptographerとか、いいバランスかなと。

木曜日, 2月 15, 2007

isFirstBang

processingでguiを扱うのにcontrolP5ライブラリを使ってるんだけど、addBang()メソッドでbangを組み込んだら、最初に実行されるsetup()メソッドの中で呼ばれてしまう。と、bangでファイルを読み込んだりしたい時に嬉しくない。のでboolean型の変数isFirstBangを作って最初のbangを回避。このcontrolP5ライブラリ、altキー押しながらドラッグすると動かせたりしてすげー。

ちなみにbangの使い方はcontrolP5型のオブジェクトに対して

.addBang("名前", x, y, width, height);

として同じ名前のメソッド

void 名前 {
...bangが押されて実行するプログラム...
}

で使えるようになる。以下、サンプル。

import controlP5.*;

ControlP5 controlP5;
boolean isFirstBang = true;

void setup() {
controlP5 = new ControlP5(this);
controlP5.addBang("openfile", 30, 30, 40, 20);
}

void openfile() {
if(isFirstBang){
println("first bang");
isFirstBang = false;
} else {
println("i want to open a file. but nothing happens now.");
}
}

void draw() {
}