We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSound,  Music Libraries › Functional example of ESS Generative Audio
Pages: 1 2 
Functional example of ESS Generative Audio (Read 6608 times)
Functional example of ESS Generative Audio
Oct 17th, 2006, 4:08am
 
I'm having trouble finding a functional example of ESS for generative audio that doesn't use SineWave or the other flavor of static waves.  I would like to manuall fill a buffer[] and pass it to ESS.  Can I do this by arraycopying data into an AudioStream?  How do I get it to play?
Re: Functional example of ESS Generative Audio
Reply #1 - Oct 19th, 2006, 11:25pm
 
a) yes, more or less like this:

Quote:
channel = new AudioChannel(blah);
sampleData = new float[channel.samples.length];
System.arraycopy(channel.samples, 0, sampleData, 0, channel.samples.length);


i guess you get the idea.

actually, i would very much prefer if ESS would be able to use something like ByteArrayInputStream for sample playback as this might simplify many things. but, alas, ESS is currently not open sourced and we depend on krister to implement this functionality... :-(

b) as usual ;-)
Re: Functional example of ESS Generative Audio
Reply #2 - Oct 24th, 2006, 1:49am
 
I switched everything to floats for a number of reasons, sound qualiy of course being the most important one.

I will be making all this open source as soon as I can, but I'm completely swamped with work and travel at the moment (as usual, grr). Let me talk to Casey and see if he has any suggestions about how to expedite the process.

Thanks!
K
Re: Functional example of ESS Generative Audio
Reply #3 - Dec 15th, 2006, 4:33am
 
The problem is I'm getting clicking.  I'm guessing this is happening because the buffer starts with the generated wave at 0 and at the end of the buffer the wave doesn't equal zero. I just mocked up this example as a sine wave (I know I can use the sine functions in ESS - I'm trying to use this for more complex buffers and I always get the clicking).  Curious if anyone has any recommendations as to a best practice in getting the clicking to go away?  It seems I would have to adjust the buffersize or samplerate make this work for a specific frequency - this doesn't seem right - my brain is off or something...


Quote:
import krister.Ess.*;

AudioStream myStream;
float[] streamBuffer;

void setup() {
 size(256,200);

 Ess.start(this);
 myStream=new AudioStream();
 streamBuffer=new float[myStream.size];
 fillAudioBuffer();
 myStream.start();
}

void fillAudioBuffer(){

 int freq = 200;
 float a = 0.0;
 float inc = TWO_PI*(freq/myStream.sampleRate);
 for(int i=0; i<streamBuffer.length; i++) {
   streamBuffer[i] = (sin(a)*.33);  
   a = a + inc;    
 }
}

void draw() {
}

void audioStreamWrite(AudioStream theStream) {
 System.arraycopy(streamBuffer,0,myStream.buffer,0,streamBuffer.length);
}

public void stop() {
 Ess.stop();
 super.stop();
}

Re: Functional example of ESS Generative Audio
Reply #4 - Dec 15th, 2006, 9:59pm
 
I've been doign a lot with this lately.. crazy 20 operator FM buffer filling stuff.. Its cool! But you need to envelope your sound.  Keep track of the progress of the way through the sound (0.0-1.0) and when you're nearing the very end fade it out.  
Code:

void fillAudioBuffer(){

int freq = 200;
float a = 0.0;
float volume=.33;
float progress=0.0;
float inc = TWO_PI*(freq/myStream.sampleRate);
for(int i=0; i<streamBuffer.length; i++) {
progress=i/streamBuffer.length; //keep track of pos
if(progress>=.99) volume=volume*.9; //fade out
streamBuffer[i] = (sin(a)*volume);
a = a + inc;
}
}


Of course once this is working, you can envelope your sound in more complex ways with things like lerp..
Re: Functional example of ESS Generative Audio
Reply #5 - Dec 15th, 2006, 10:16pm
 
Thanks, nice easy example of fade out but this code still clicks, just not as loud.  (btw, had to add explicit conversion of float to your example).  

Code:

progress=(float)i/(float)streamBuffer.length; //keep track of pos


I'm struggling with where I need to make my adjustments make this audio buffer seamless - no clicking.  I want to be able to play a solid complex tone without a click every 1/4 of a second (I can of course change my buffer length to match the sample rate then I only get a click every second but I still get the click).  Not sure what I'm doing wrong.

Some math that will probably reveal my faulty assumptions:

If I set my sampleRate at 44100 that means I'm getting 44100 samples per second (?).

If I set my bufferSize to 44100 then I'll have 1 buffer node for each sample.

With a sine frequency of 200Hz (200 cycled per second) I should have 200 complete sine waves in 1 second.  However, when I put this into the code above, the first sample is: 0, the last sample is: -0.26354966.  Hence my beat.  I should be able to calculate a sampleRate and bufferSize that will give me a continuous sine wave but I'm missing something here.
Re: Functional example of ESS Generative Audio
Reply #6 - Dec 15th, 2006, 10:39pm
 
If you want to do this stuff for live performance, you'd probably be better off with something like MaxMSP or PD :-\.

If you're doing this for recording/studio work, then switching to audiochannels instead of streams will make it easier to control exactly whats being created and written (in my experience).  Because you create it first, then play it back. (thats what I do).

That said, as long as the beginning and end of each buffer is zero, and there are no jumps in your signal, there *should* be no clicking.   I guess it all depends on how the stream buffer gets updated.

Try writing a buffer and then displaying the waveform image, so you can visually examine what the click artifact looks like.  This always helps me immensely.
Re: Functional example of ESS Generative Audio
Reply #7 - Dec 15th, 2006, 11:07pm
 
Thanks, yeah, I've been using Max/MSP and before that PD but am trying to cobble something together as a Processing program and also would just generally like to figure this out.  Guess I'm diving into the Curtis Rhodes synth bible tonight.
Re: Functional example of ESS Generative Audio
Reply #8 - Dec 16th, 2006, 9:28pm
 
Well, just wanted to report back to inform that the problem is definitely my math calculation and not due to delay in the audio buffer copying.  I resolved this by just using a square waverform which I could definitively set to oscilate in regular phases on the borders between buffer copies.

So I definitely have to adjust buffersize to the frequency to ensure my waves phase correctly as the buffer is repeated. Now to resolve this for sine waves...

Code if anyone is interested:

Code:


import krister.Ess.*;

AudioStream myStream;
float[] streamBuffer;

void setup() {
size(256,200);

Ess.start(this);
myStream=new AudioStream();
myStream.sampleRate(10000);
myStream.bufferSize(5000);
streamBuffer=new float[myStream.size];
fillAudioBuffer();
myStream.start();
}

void fillAudioBuffer(){
int wl = 4;
int p = 0;
int amp = 1;
float progress=0.0;
for(int i=0; i<streamBuffer.length; i++) {
if ( p >= wl ) {
p = 0;
amp = amp * (-1);
}
streamBuffer[i] = amp;
p++;
}
}

void draw() {
}

void audioStreamWrite(AudioStream theStream) {
System.arraycopy(streamBuffer,0,myStream.buffer,0,streamBuffer.length);
}

public void stop() {
Ess.stop();
super.stop();
}
Re: Functional example of ESS Generative Audio
Reply #9 - Dec 31st, 2006, 9:36pm
 
Please do report back here when you find a solution for sine waves. I've been playing with those today, linking the frequency of the sine wave to the horizontal position of the mouse in the sketch and trying to get the frequency to change smoothly (no clicks). As it stands, I'm getting lots of clicks, every time time buffer is refilled, I imagine.

I've tried fading the buffer at the ends, but this results in a pulsing tone rather than a continuous tone (but no clicks!). I've also tried using two oscillators and crossfading between them when the frequency changes, but this is just as clicky as using a single oscillator. Anyway, I'll keep banging away at it, I guess.
Re: Functional example of ESS Generative Audio
Reply #10 - Jan 1st, 2007, 12:44am
 
It is all a matter of phase and ending on zero.  You have to adjust your buffer size so that you have only complete waves (a full cycle zero to zero including a peak and a trough).  Basically you have to adjust the buffer in such a way that if you repeated the buffer over and over that it would be seamless and you wouldn't be able to tell where the buffer borders were.  

Don't have an example with a sine wave handy but wanted to post back.
Re: Functional example of ESS Generative Audio
Reply #11 - Jan 1st, 2007, 12:58am
 
I decided to try writing my own sine wave generator. This Sine class can change frequency during runtime without clicks and pops. One "problem" is that during the transition the tone is not a pure sine tone because it is crossfading from the current frequency to the newly requested frequency. Also, for the moment the sample rate is fixed at whatever you instantiante it with. You can use this the same way you'd use the Ess class SineWave, though it's not yet as full-featured. The generate functions return a boolean so that you can do something when a crossfade happens (I was using it as a flag to investigate the seam between the previous buffer and the newly filled one).

Code:

class Sine
{
private float freq, newFreq;
private float amp;
private float stepSize;
private float step;

Sine(float frequency, float amplitude, float sampleRate)
{
freq = frequency * TWO_PI;
newFreq = freq;
amp = amplitude;
stepSize = 1/sampleRate;
step = 0;
}

void setFreq(float f)
{
newFreq = f * TWO_PI;
}

boolean generate(AudioOutput ao)
{
float[] buff = new float[ao.buffer.length];
boolean alert = generate(buff);
arraycopy(buff, 0, ao.buffer2, ao.buffer.length, buff.length);
arraycopy(buff, 0, ao.buffer, 0, buff.length);
return alert;
}

boolean generate(float[] buff)
{
boolean alert = freq != newFreq;
float a;
float b;
float mix;
for ( int i = 0; i < buff.length; i++ )
{
if ( freq != newFreq )
{
mix = map(i, 0, buff.length-1, 0, amp);
a = amp - mix;
b = mix;
buff[i] = a*sin(freq*step) + b*sin(newFreq*step);
}
else
{
buff[i] = amp*sin(freq*step);
}
step += stepSize;
}
freq = newFreq;
return alert;
}
}


Sorry about the messed up indenting, it looks right in the text box, I swear.
Re: Functional example of ESS Generative Audio
Reply #12 - Jan 3rd, 2007, 12:22am
 
Here's a better version of the generate() function in the above Sine class. This version gradually transitions the frequency to the new target frequency, rather than crossfading. An additional bonus is that you can control the speed of the portamento.

Code:

boolean generate(float[] buff)
{
boolean alert = freq != newFreq;
for ( int i = 0; i < buff.length; i++ )
{
buff[i] = amp*sin(freq*TWO_PI*step);
if ( abs(freq-newFreq) < 0.001f ) freq = newFreq;
else if ( freq < newFreq ) freq += 0.1f;
else if ( freq > newFreq ) freq -= 0.1f;
step += stepSize;
if ( step > 1/freq ) step %= 1/freq;
}
return alert;
}


Oh, these other changes to the class are also necessary:

Code:

Sine(float f, float a, float s)
{
freq = f;
newFreq = freq;
amp = a;
stepSize = 1/s;
step = 0;
}

void setFreq(float f)
{
newFreq = f;
}
Re: Functional example of ESS Generative Audio
Reply #13 - Jan 6th, 2007, 3:35am
 
hi ddf

would you mind posting your complete processing code? can't quite follow how you're putting it all together...

thx
Re: Functional example of ESS Generative Audio
Reply #14 - Jan 9th, 2007, 4:22pm
 
Hello
I tried this last night.
On a mac G5 and a mini-mac intel there are problems if the buffer is less then 4096.
Sorry for the not very clean code.
If it is not working, kill the code parts with font ...

Code:

import krister.Ess.*;
AudioStream myStream;

AudioChannel myChannel;
FFT myFFT;
int bufferSize;
int bufferDuration;

// ----Einstellungen---
float zoomY=100;

double ampScale = 0.5;

double valAlt=0;
double dTime=0;
double dTimeInc=0;
double tonTimeInc=0;
double tonTime=0;
float oneCycle =0;
double freq;

Handle hFreq;
Handle hAmp;
Handle hSpez;
float sampleRate = 0;

PFont font1;

void draw(){
int i;
int x=10;



background(153);

drawRegler();
drawSpectrum(10,300,100);
stroke(0);
fill(0);


text("Time:"+dTime, 15, 30);
text("Frequenz:"+freq, 15, 50);


fill(200,50,50,50);
rect(10, 200, 512, 200);
line (10,300,512+10,300);

float firstVal= myStream.buffer2[0];
for( i = 0; i < myStream.buffer2.length-1; i++){
if( (myStream.buffer2[i]>=0)&(myStream.buffer2[i+1]<=0)){
break;
}

}
int startI=i;
int stepX=myStream.buffer2.length/512;
stroke(255);
for( i = startI; i < myStream.buffer2.length-stepX; i=i+stepX){

line(x,300 - myStream.buffer2[i]*zoomY,x+1,300 - myStream.buffer2[i+stepX]*zoomY);
x++;
}


}


void setup(){

size(600,440);
smooth();

font1 = loadFont("Geneva-16.vlw");
textFont(font1, 14);


background(102);

setupRegler(3,10,80,200,540);
hFreq=handles[0];
hAmp=handles[1];
hSpez=handles[2];
hAmp.length=200;
hFreq.length=100;
hSpez.length=0;
sampleRate =44100;

Ess.start(this);
myStream=new AudioStream(8192/2,sampleRate); //2048 knackst schon

sampleRate=myStream.sampleRate;
bufferSize=myStream.buffer.length;


println("BufferSize="+bufferSize+"\nSampleRate="+sampleRate);

dTimeInc=1./sampleRate;
bufferSize=myStream.buffer.length;
bufferDuration=myStream.ms(bufferSize);
myFFT=new FFT(2048);
myStream.start();

// noSmooth();
drawRegler();
}



void audioStreamWrite(AudioStream theStream) {

double vL = 0;
ampScale=hAmp.val/800.;

double spez=hSpez.val*0.00005;

for (int i=0;i<theStream.size;i++) {
freq=hFreq.val*2.;
tonTimeInc =freq/sampleRate;

tonTime+=tonTimeInc;

vL=Math.sin(TWO_PI*tonTime*(1+(valAlt*valAlt)));
valAlt=vL*spez;
theStream.buffer[i]=(float)(vL*ampScale);

dTime+=dTimeInc;
}


}


//----REGLER----
//===========================//

Handle[] handles;
int reglerAnz;
int reglerBreite;
int reglerHoehe;
int reglerX;
int reglerY;
int reglerBoxSize=12;
void setupRegler(int vreglerAnz,int vX,int vY,int vH,int vB )
{

reglerAnz=vreglerAnz;
reglerBreite=vB;
println("breite="+reglerBreite);
reglerHoehe=vH;
reglerX=50;//vX;
reglerY=vY;
handles = new Handle[reglerAnz];
int hsize =1;
for(int i=0; i<reglerAnz; i++) {
handles[i] = new Handle(reglerX, reglerY+10+i*15, 0, reglerBoxSize, handles);
}
}

void drawRegler()
{
background(153);

for(int i=0; i<reglerAnz; i++) {
handles[i].update();
handles[i].display();
}

fill(0);
}


void drawSpectrum(int x,int y,int h) {
noStroke();

myFFT.getSpectrum(myStream);

for (int i=0; i<512; i++) {
float temp=myFFT.spectrum[i]*175;
rect(x+i,y+h,1,-temp);
}


}

void mouseReleased()
{
for(int i=0; i<reglerAnz; i++) {
handles[i].release();
}
}

class Handle
{
int x, y;
int boxx, boxy;
int length;
int val;
int size;
boolean over;
boolean press;
boolean locked = false;
boolean otherslocked = false;
Handle[] others;

Handle(int ix, int iy, int il, int is, Handle[] o)
{
x = ix;
y = iy;
length = il;
size = is;
boxx = x+length - size/2;
boxy = y - size/2;
others = o;
}

void update()
{
boxx = x+length;
boxy = y - size/2;

for(int i=0; i<others.length; i++) {
if(others[i].locked == true) {
otherslocked = true;
break;
}
else {
otherslocked = false;
}
}

if(otherslocked == false) {
over();
press();
}

if(press) {

length = lock(mouseX-reglerX-size/2, 0, reglerBreite-size-1);

}
if(val!=length){
val=length ;


}
}



void over()
{
if(overRect(boxx, boxy, size, size)) {
over = true;
}
else {
over = false;
}
}

void press()
{
if(over && mousePressed || locked) {
press = true;
locked = true;
}
else {
press = false;
}
}

void release()
{
locked = false;
}

void display()
{
line(x, y, x+length, y);
fill(255);
stroke(0);
rect(boxx, boxy, size, size);
if(over || press) {
line(boxx, boxy, boxx+size, boxy+size);
line(boxx, boxy+size, boxx+size, boxy);
}

}
}

boolean overRect(int x, int y, int width, int height)
{
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
}
else {
return false;
}
}

int lock(int val, int minv, int maxv)
{
return min(max(val, minv), maxv);
}



public void stop() {
Ess.stop();
super.stop();
}

Pages: 1 2