Friday, August 11, 2006
Tuesday, December 14, 2004
Documentation
Here is the application we filled out for the show, regarding context and purpose of the project:
Description
Punching bags are for exercise and stress relief. This punching bag indicates your progress with solid colors and sounds chosen to refelect intensity of punches.
We wanted to do something with exercise and a sense of humor. Initially we thought about baseball and other sports, but focused on boxing because it's something that everyone can do and is familiar with.
Audience
ITP Students and visitors who want to take out all their frustrations, tech and otherwise. Users can slap at it, punch the hell out it, kick it, etc.
User Scenario
Users will approach the piece, and if they choose to hit it, will get an immediate response. As they punch, they may realize that there is a color-coded system for advancement. They will also enjoy the spectacle of punching the bag and changing the colors and sounds.
Project References, Research and Literature
Boxers historically get a mixed rap. While Mohammed Ali is a great of the sport and a timeless winner, Tyson is a more notorious character.
Rocky won best film in the 1980's signifying its universal appeal. Boxing today draws crowds in Vegas and afar, woman now participate too.
Having tested the interactive punching bag, we received really positive feedback from students in the PComp lounge and Commons Area.
We demonstrated the punching bag Tuesday night for the pcomp projects presentation scheduled in the Japanese Room.
Here is Wlodek's excellent documentation for the project.
As soon as I can get it off of the two PCs, I'll post here the Illustrator source files and gifs for the graphics. I think that redundancy for pcomp projects is important considering that machines on occasion crap out.
We ended up using neither the crossover nor video in Processing; less is more.
The class demonstration went very well, Andrew invited 3 guests Alison, Colin, and a film maker to give us unbiased evaluation. Their main comment was to use the sound trigger more effectively, but otherwise they enjoyed using it.
Description
Punching bags are for exercise and stress relief. This punching bag indicates your progress with solid colors and sounds chosen to refelect intensity of punches.
We wanted to do something with exercise and a sense of humor. Initially we thought about baseball and other sports, but focused on boxing because it's something that everyone can do and is familiar with.
Audience
ITP Students and visitors who want to take out all their frustrations, tech and otherwise. Users can slap at it, punch the hell out it, kick it, etc.
User Scenario
Users will approach the piece, and if they choose to hit it, will get an immediate response. As they punch, they may realize that there is a color-coded system for advancement. They will also enjoy the spectacle of punching the bag and changing the colors and sounds.
Project References, Research and Literature
Boxers historically get a mixed rap. While Mohammed Ali is a great of the sport and a timeless winner, Tyson is a more notorious character.
Rocky won best film in the 1980's signifying its universal appeal. Boxing today draws crowds in Vegas and afar, woman now participate too.
Having tested the interactive punching bag, we received really positive feedback from students in the PComp lounge and Commons Area.
We demonstrated the punching bag Tuesday night for the pcomp projects presentation scheduled in the Japanese Room.
Here is Wlodek's excellent documentation for the project.
As soon as I can get it off of the two PCs, I'll post here the Illustrator source files and gifs for the graphics. I think that redundancy for pcomp projects is important considering that machines on occasion crap out.
We ended up using neither the crossover nor video in Processing; less is more.
The class demonstration went very well, Andrew invited 3 guests Alison, Colin, and a film maker to give us unbiased evaluation. Their main comment was to use the sound trigger more effectively, but otherwise they enjoyed using it.
Monday, December 06, 2004
12/3 Working Code - Testing Comments
We are getting bad values from the Piezo, possibly because of long wires to the bread board causing interference.
Here is the latest Processing Code:
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then
statements //Note the Sonia code folder goes into the
sketch folder
//web site to
scrape:http://www.dhs.gov/dhspublic/display?theme=29
//sounds: http://www.findsounds.com/ISAPI/search.dll
//Settings for display of color images
int picDislayTime =400; //time imageis
displayed in milliseconds
int numOfPics = 5; //number of
images in image array for colors
BImage[] colors = new BImage[numOfPics]; //new array
of up for displaying color photos
int whichImage = 0; //to display
appropriate image
boolean showing = false; //for
checking whether or not time of the images displayed
has elapsed
int startTime; //variable
for timer
float previousLevel = 0; //to check
previous mic input
float meterData = 0;
//settings for display of homepage image
int introDisplayTime = 30000; //time after
last sensor input that "homepage" image gets displayed
BImage start; //the "home
page" image
int waitingTime; //
boolean waiting = false;
//settings for playing sounds
int numOfSounds = 5; //a sound
for each color
Sample[] thunder = new Sample[numOfSounds]; //array to
hold each sound
//serial piezo
float piezo = 0;
float combinedAverageData = 0;
void setup()
{
beginSerial(); // Default start serial at 9600
baud
serialWrite(65); //sent message to pic to
begin serial communication
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and
return 256 FFT frequency bands.
size(800,600);
for(int j=1 ; j<6 ; j++)
{
colors [j-1] = loadImage ("color" + j + ".gif");
thunder[j-1] = new Sample("thunder"+ j + ".wav");
}
start = loadImage("homepict.gif");
startTime = millis();
background (0);
}
void loop()
{
soundShow(); //Show appropriate image based on
input from microphone
if (showing)
{
image(colors[whichImage], 0, 0);
}
if ((millis() - startTime > picDislayTime))
{
showing = false;
}
intro(); //display homepage image if no
input is received from sensors
}
void soundShow()//Show image based on input from
microphone
{
meterData = 250 * LiveInput.getLevel(Sonia.LEFT);
combinedAverageData = (meterData + piezo)/2;
for(int i = 100 ; i > 10 ; i-=20)
{
int j = i/20;
if (!showing)
{
if (combinedAverageData > i)
{
whichImage = j - 1;
thunder[j-1].play();
showing = true;
startTime = millis();
previousLevel = i + 20;
println (meterData+ " " +piezo+ "
"+combinedAverageData);
}
}
}
}
void intro()
{
if ((combinedAverageData < 10) && (!waiting))
{
waiting = true;
waitingTime = millis();
}
else if (combinedAverageData >= 10) {
waiting = false;
}
if ((millis() - waitingTime > introDisplayTime) &&
(waiting))
{
waiting = false;
image(start, 300, 0);
}
}
void serialEvent() //automatic serial listener
{
piezo = serial; // save messages to variable
"piezo"
serialWrite(65); // send message to PIC
}
// Safely close the sound engine upon Browser
shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
Here is the latest Processing Code:
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then
statements //Note the Sonia code folder goes into the
sketch folder
//web site to
scrape:http://www.dhs.gov/dhspublic/display?theme=29
//sounds: http://www.findsounds.com/ISAPI/search.dll
//Settings for display of color images
int picDislayTime =400; //time imageis
displayed in milliseconds
int numOfPics = 5; //number of
images in image array for colors
BImage[] colors = new BImage[numOfPics]; //new array
of up for displaying color photos
int whichImage = 0; //to display
appropriate image
boolean showing = false; //for
checking whether or not time of the images displayed
has elapsed
int startTime; //variable
for timer
float previousLevel = 0; //to check
previous mic input
float meterData = 0;
//settings for display of homepage image
int introDisplayTime = 30000; //time after
last sensor input that "homepage" image gets displayed
BImage start; //the "home
page" image
int waitingTime; //
boolean waiting = false;
//settings for playing sounds
int numOfSounds = 5; //a sound
for each color
Sample[] thunder = new Sample[numOfSounds]; //array to
hold each sound
//serial piezo
float piezo = 0;
float combinedAverageData = 0;
void setup()
{
beginSerial(); // Default start serial at 9600
baud
serialWrite(65); //sent message to pic to
begin serial communication
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and
return 256 FFT frequency bands.
size(800,600);
for(int j=1 ; j<6 ; j++)
{
colors [j-1] = loadImage ("color" + j + ".gif");
thunder[j-1] = new Sample("thunder"+ j + ".wav");
}
start = loadImage("homepict.gif");
startTime = millis();
background (0);
}
void loop()
{
soundShow(); //Show appropriate image based on
input from microphone
if (showing)
{
image(colors[whichImage], 0, 0);
}
if ((millis() - startTime > picDislayTime))
{
showing = false;
}
intro(); //display homepage image if no
input is received from sensors
}
void soundShow()//Show image based on input from
microphone
{
meterData = 250 * LiveInput.getLevel(Sonia.LEFT);
combinedAverageData = (meterData + piezo)/2;
for(int i = 100 ; i > 10 ; i-=20)
{
int j = i/20;
if (!showing)
{
if (combinedAverageData > i)
{
whichImage = j - 1;
thunder[j-1].play();
showing = true;
startTime = millis();
previousLevel = i + 20;
println (meterData+ " " +piezo+ "
"+combinedAverageData);
}
}
}
}
void intro()
{
if ((combinedAverageData < 10) && (!waiting))
{
waiting = true;
waitingTime = millis();
}
else if (combinedAverageData >= 10) {
waiting = false;
}
if ((millis() - waitingTime > introDisplayTime) &&
(waiting))
{
waiting = false;
image(start, 300, 0);
}
}
void serialEvent() //automatic serial listener
{
piezo = serial; // save messages to variable
"piezo"
serialWrite(65); // send message to PIC
}
// Safely close the sound engine upon Browser
shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
Tuesday, November 30, 2004
Processing Code 11/29
There is a problem with the .wav and timing of the color changes. We are wondering if this is a Processing or Sonia issue. This code uses for loops and arrays to cut down on file size.
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then statements
//Note the Sonia code folder goes into the sketch folder
//web site to scrape: http://www.dhs.gov/dhspublic/display?theme=29
//sounds: http://www.findsounds.com/ISAPI/search.dll
int numOfPics = 5; //number of images in image array for colors
BImage[] colors = new BImage[numOfPics]; //new array of up for displaying color photos
int picDislayTime = 100000; //time image is displayed in milliseconds
int whichImage = 0;
int startTime;
Sample thunder;
float previousLevel = 0;
boolean showing = false;
void setup()
{
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and return 256 FFT frequency bands.
thunder = new Sample("thunder.wav");
size(640,480);
for(int j=0 ; j<5 ; j++)
{
int m = j+1;
colors[j] = loadImage("color" + m + ".gif");
}
startTime = millis();
}
void loop()
{
showImage(); //Show appropriate image based on input from microphone
for(int i = 5 ; i > 0 ; i-=1)
{
int j = i-1;
if (showing)
if (whichImage == i) {
image(colors[j], 0, 0);
}
if ((millis() - startTime > picDislayTime) || (1500 * LiveInput.getLevel(Sonia.LEFT) > previousLevel))
/* || (1000 * LiveInput.getLevel(Sonia.LEFT) < previousLevel)*/{
showing = false;
}
}
}
void showImage()//Show image based on input from microphone
{
float meterDataLeft = 1500 * LiveInput.getLevel(Sonia.LEFT);//avg this w/ serial in
for(int i = 800 ; i > 100 ; i-=160)
{
int j = i/160;
if (!showing)
{
if (meterDataLeft > i)
{
whichImage = j;
println(j);
thunder.play();
showing = true;
startTime = millis();
previousLevel= meterDataLeft;
}
}
}
}
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
Saturday, November 27, 2004
Thanksgiving Processing Code
This version has a timer for 10 seconds and stays on a level till the user hits it up to the next or until the 10 seconds are up. We will have a legend so they know what the colors mean.
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then statements
//Note the Sonia code folder goes into the sketch folder
BImage color1;
BImage color2;
BImage color3;
BImage color4;
BImage color5;
/*int numOfPics = 150; //number of images in image array for video sequence
BImage[] carlos = new BImage[numOfPics]; //new array of up to 224 photos
int numOfImages = 100; //number of images in image array for background images
BImage[] boxing = new BImage[numOfImages]; //new array of photos*/
int a = 0; // variable for counting through the display of photos
int picDislayTime = 10000; //time image is displayed in milliseconds
int movDisplayTime = 70; //time image is displayed in milliseconds
int whichImage = 0;
int startTime;
int startTimeMov;
float previousLevel = 0;
//float meterLevel = liveinput.getlevel
boolean showing = false;
boolean slowDown = false;
void setup(){
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and return 256 FFT frequency bands.
size(640,480);
colorMode(RGB, 255, 255 ,255, 100);//need this comment later for tinting, etc
/*for(int j=0; j int m = j + 1;
carlos[j] = loadImage("boxing" + m + ".jpg");
}*/
color1 = loadImage("color1.gif");
color2 = loadImage("color2.gif");
color3 = loadImage("color3.gif");
color4 = loadImage("color4.gif");
color5 = loadImage("color5.gif");
/*for(int i=0; i int n = i + 1;
carlos[i] = loadImage("carlos" + n + ".gif");
}*/
startTime = millis();
}
void loop(){
background(0,0,0);
showImage(); //Show appropriate image based on input from microphone
if (showing) {
if (whichImage == 5) {
image(color5, 0, 0);
}
else if (whichImage == 4) {
image(color4,0,0);
}
else if (whichImage == 3) {
image(color3,0,0);
}
else if (whichImage == 2) {
image(color2,0,0);
}
else if (whichImage == 1) {
image(color1,0,0);
}
if (millis() - startTime > picDislayTime) {
showing = false;
}
if (1000 * LiveInput.getLevel(Sonia.LEFT) > previousLevel) {
showing = false;
}
}
}
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
void showImage()//Show appropriate background image based on input from microphone
{
float meterDataLeft = 1000 * LiveInput.getLevel(Sonia.LEFT);
println(meterDataLeft);
if (!showing) {
if (meterDataLeft > 740) {
previousLevel= meterDataLeft;
whichImage = 5;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 580) {
previousLevel= meterDataLeft;
whichImage = 4;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 420) {
previousLevel= meterDataLeft;
whichImage = 3;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 260) {
previousLevel= meterDataLeft;
whichImage = 2;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 100) {
whichImage = 1;
showing = true;
startTime = millis();
previousLevel= meterDataLeft;
}
}
}
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then statements
//Note the Sonia code folder goes into the sketch folder
BImage color1;
BImage color2;
BImage color3;
BImage color4;
BImage color5;
/*int numOfPics = 150; //number of images in image array for video sequence
BImage[] carlos = new BImage[numOfPics]; //new array of up to 224 photos
int numOfImages = 100; //number of images in image array for background images
BImage[] boxing = new BImage[numOfImages]; //new array of photos*/
int a = 0; // variable for counting through the display of photos
int picDislayTime = 10000; //time image is displayed in milliseconds
int movDisplayTime = 70; //time image is displayed in milliseconds
int whichImage = 0;
int startTime;
int startTimeMov;
float previousLevel = 0;
//float meterLevel = liveinput.getlevel
boolean showing = false;
boolean slowDown = false;
void setup(){
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and return 256 FFT frequency bands.
size(640,480);
colorMode(RGB, 255, 255 ,255, 100);//need this comment later for tinting, etc
/*for(int j=0; j
carlos[j] = loadImage("boxing" + m + ".jpg");
}*/
color1 = loadImage("color1.gif");
color2 = loadImage("color2.gif");
color3 = loadImage("color3.gif");
color4 = loadImage("color4.gif");
color5 = loadImage("color5.gif");
/*for(int i=0; i
carlos[i] = loadImage("carlos" + n + ".gif");
}*/
startTime = millis();
}
void loop(){
background(0,0,0);
showImage(); //Show appropriate image based on input from microphone
if (showing) {
if (whichImage == 5) {
image(color5, 0, 0);
}
else if (whichImage == 4) {
image(color4,0,0);
}
else if (whichImage == 3) {
image(color3,0,0);
}
else if (whichImage == 2) {
image(color2,0,0);
}
else if (whichImage == 1) {
image(color1,0,0);
}
if (millis() - startTime > picDislayTime) {
showing = false;
}
if (1000 * LiveInput.getLevel(Sonia.LEFT) > previousLevel) {
showing = false;
}
}
}
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
void showImage()//Show appropriate background image based on input from microphone
{
float meterDataLeft = 1000 * LiveInput.getLevel(Sonia.LEFT);
println(meterDataLeft);
if (!showing) {
if (meterDataLeft > 740) {
previousLevel= meterDataLeft;
whichImage = 5;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 580) {
previousLevel= meterDataLeft;
whichImage = 4;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 420) {
previousLevel= meterDataLeft;
whichImage = 3;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 260) {
previousLevel= meterDataLeft;
whichImage = 2;
showing = true;
startTime = millis();
}
else if (meterDataLeft > 100) {
whichImage = 1;
showing = true;
startTime = millis();
previousLevel= meterDataLeft;
}
}
}
Wednesday, November 24, 2004
Updated Final Project Code (Processing)
We tested the project and received very positive feedback from users.
To run serial with Sonia at the same time, make sure that win32Comm.dll is in the same folder.
We are using colors to indicate progress
.
.
. . We need a stepped motion and a timer. We discussed using the Piezo for serial input for a meter.
Priorities:
Set up color program
Set up time delay
Set up audio and serial from strip
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then statements
//Note the Sonia code folder goes into the sketch folder
BImage b;
BImage c;
//int numOfPics = 150; //number of images in image array for video sequence
//BImage[] carlos = new BImage[numOfPics]; //new array of up to 224 photos
/*int numOfImages = 100; //number of images in image array for background images
BImage[] boxing = new BImage[numOfImages]; //new array of photos*/
int a = 0; // variable for counting through the display of photos
int picDislayTime = 1000; //time image is displayed in milliseconds
int movDisplayTime = 70; //time image is displayed in milliseconds
int whichImage = 0;
int startTime;
int startTimeMov;
boolean showing = false;
boolean slowDown = false;
void setup(){
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and return 256 FFT frequency bands.
beginSerial();
size(640,480);
colorMode(RGB, 255, 255 ,255, 100);//need this comment later for tinting, etc
/*for(int j=0; j int m = j + 1;
carlos[j] = loadImage("boxing" + m + ".jpg");
}*/
b = loadImage("boxing1NL.jpg");
c = loadImage("bsuit.gif");
/*for(int i=0; i int n = i + 1;
carlos[i] = loadImage("carlos" + n + ".gif");
}*/
startTime = millis();
}
void loop(){
background(0,0,0);
//showImage(); //Show appropriate image based on input from microphone
if (showing) {
if (whichImage == 1) {
image(b, 0, 0);
} else if (whichImage == 2) {
image(c,0,0);
}
if (millis() - startTime > picDislayTime) {
showing = false;
}
}
/*showMeterLevel(); //Show simulated movie clip - acts like a meter based on volume from mic
if (slowDown) {
image (carlos[a], 0, 0, carlos[0].width, carlos[0].height - mouseY); //display each image in sequence
if (millis() - startTimeMov > movDisplayTime){
slowDown = false;
}
}*/
}
/*void showMeterLevel(){//Show simulated movie clip - acts like a meter based on volume from mic
float meterDataLeft = 1000 * LiveInput.getLevel(Sonia.LEFT);
float meterDataRight = 1000 * LiveInput.getLevel(Sonia.RIGHT);
if (!slowDown) {
image (carlos[a], 0, 0, carlos[0].width, carlos[0].height - mouseY); //display each image in sequence
a = a + 1;
if ( a >= numOfPics ) {
a = 0;
}
slowDown = true;
startTimeMov = millis();
}
}*/
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
To run serial with Sonia at the same time, make sure that win32Comm.dll is in the same folder.
We are using colors to indicate progress
.
.
. . We need a stepped motion and a timer. We discussed using the Piezo for serial input for a meter.
Priorities:
Set up color program
Set up time delay
Set up audio and serial from strip
// CODE
// SONIA V2.5 -- Audio Live Stream.
//http://www.pitaru.com/sonia/
//Goal is to capture audio data and parse into if/then statements
//Note the Sonia code folder goes into the sketch folder
BImage b;
BImage c;
//int numOfPics = 150; //number of images in image array for video sequence
//BImage[] carlos = new BImage[numOfPics]; //new array of up to 224 photos
/*int numOfImages = 100; //number of images in image array for background images
BImage[] boxing = new BImage[numOfImages]; //new array of photos*/
int a = 0; // variable for counting through the display of photos
int picDislayTime = 1000; //time image is displayed in milliseconds
int movDisplayTime = 70; //time image is displayed in milliseconds
int whichImage = 0;
int startTime;
int startTimeMov;
boolean showing = false;
boolean slowDown = false;
void setup(){
Sonia.start(this); // Start Sonia engine.
LiveInput.start(256); // Start LiveInput and return 256 FFT frequency bands.
beginSerial();
size(640,480);
colorMode(RGB, 255, 255 ,255, 100);//need this comment later for tinting, etc
/*for(int j=0; j
carlos[j] = loadImage("boxing" + m + ".jpg");
}*/
b = loadImage("boxing1NL.jpg");
c = loadImage("bsuit.gif");
/*for(int i=0; i
carlos[i] = loadImage("carlos" + n + ".gif");
}*/
startTime = millis();
}
void loop(){
background(0,0,0);
//showImage(); //Show appropriate image based on input from microphone
if (showing) {
if (whichImage == 1) {
image(b, 0, 0);
} else if (whichImage == 2) {
image(c,0,0);
}
if (millis() - startTime > picDislayTime) {
showing = false;
}
}
/*showMeterLevel(); //Show simulated movie clip - acts like a meter based on volume from mic
if (slowDown) {
image (carlos[a], 0, 0, carlos[0].width, carlos[0].height - mouseY); //display each image in sequence
if (millis() - startTimeMov > movDisplayTime){
slowDown = false;
}
}*/
}
/*void showMeterLevel(){//Show simulated movie clip - acts like a meter based on volume from mic
float meterDataLeft = 1000 * LiveInput.getLevel(Sonia.LEFT);
float meterDataRight = 1000 * LiveInput.getLevel(Sonia.RIGHT);
if (!slowDown) {
image (carlos[a], 0, 0, carlos[0].width, carlos[0].height - mouseY); //display each image in sequence
a = a + 1;
if ( a >= numOfPics ) {
a = 0;
}
slowDown = true;
startTimeMov = millis();
}
}*/
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
Sunday, November 14, 2004
Bryce Wolkowitz Gallery Visit
I went to the "Sign Language" exhibit by Tatsuo Miyajima and Ben Rubin. Miyajim's pieces centers on numbers in various configurations. "Counter me on No. 3" is made of neon and steel and reflects the viewer on close inspection. The 2 Ben Rubin pieces "Instability" were really cool. I looked for a projector to see how the words reflected on the LED and realized that there's probably something within the tubes which generates these characters.
Here is the gallery web site: http://www.brycewolkowitz.com The building houses other galleries too.
Here is the gallery web site: http://www.brycewolkowitz.com The building houses other galleries too.

