Fluid waveform layers (#53)
* layers cause race conditions * front method keeps race conditions from happening * allow for image color to be base on alpha * bump * bump * more tests * updated FluidWaveform help file examplesnix
parent
a918e8f6e4
commit
ec17cdc964
@ -1,247 +1,432 @@
|
|||||||
FluidViewer {
|
FluidViewer {
|
||||||
var categoryColors;
|
|
||||||
|
|
||||||
createCatColors {
|
createCatColors {
|
||||||
|
^FluidViewer.createCatColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
*createCatColors {
|
||||||
// colors from: https://github.com/d3/d3-scale-chromatic/blob/main/src/categorical/category10.js
|
// colors from: https://github.com/d3/d3-scale-chromatic/blob/main/src/categorical/category10.js
|
||||||
categoryColors = "1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf".clump(6).collect{
|
^"1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf".clump(6).collect{
|
||||||
arg six;
|
arg six;
|
||||||
Color(*six.clump(2).collect{
|
Color(*six.clump(2).collect{
|
||||||
arg two;
|
arg two;
|
||||||
"0x%".format(two).interpret / 255;
|
"0x%".format(two).interpret / 255;
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FluidWaveform : FluidViewer {
|
FluidWaveformAudioLayer {
|
||||||
classvar <lin = 0, <log = 1;
|
var audioBuffer, waveformColor;
|
||||||
var <win;
|
|
||||||
|
|
||||||
*new {
|
*new {
|
||||||
arg audioBuffer, indicesBuffer, featuresBuffer, parent, bounds, lineWidth = 1, waveformColor, stackFeatures = false, imageBuffer, imageColorScheme = 0, imageAlpha = 1, normalizeFeaturesIndependently = true, colorScaling = 1;
|
arg audioBuffer, waveformColor;
|
||||||
^super.new.init(audioBuffer,indicesBuffer, featuresBuffer, parent, bounds, lineWidth, waveformColor,stackFeatures,imageBuffer,imageColorScheme,imageAlpha,normalizeFeaturesIndependently,colorScaling);
|
^super.new.init(audioBuffer,waveformColor);
|
||||||
}
|
|
||||||
|
|
||||||
close {
|
|
||||||
win.close;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadColorFile {
|
|
||||||
arg filename;
|
|
||||||
^CSVFileReader.readInterpret(FluidFilesPath("../Resources/color-schemes/%.csv".format(filename))).collect{
|
|
||||||
arg row;
|
|
||||||
Color.fromArray(row);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
arg audio_buf, slices_buf, feature_buf, parent_, bounds, lineWidth, waveformColor,stackFeatures = false, imageBuffer, imageColorScheme = 0, imageAlpha = 1, normalizeFeaturesIndependently = true, colorScaling = 1;
|
arg audioBuffer_, waveformColor_;
|
||||||
Task{
|
|
||||||
var sfv, categoryCounter = 0, xpos, ypos;
|
|
||||||
|
|
||||||
waveformColor = waveformColor ? Color(*0.6.dup(3));
|
audioBuffer = audioBuffer_;
|
||||||
|
waveformColor = waveformColor_ ? Color.gray;
|
||||||
this.createCatColors;
|
}
|
||||||
|
|
||||||
if(bounds.isNil && imageBuffer.notNil,{
|
|
||||||
bounds = Rect(0,0,imageBuffer.numFrames,imageBuffer.numChannels);
|
|
||||||
});
|
|
||||||
|
|
||||||
bounds = bounds ? Rect(0,0,800,200);
|
draw {
|
||||||
|
arg win, bounds;
|
||||||
|
fork({
|
||||||
|
var path = "%%_%_FluidWaveform.wav".format(PathName.tmp,Date.localtime.stamp,UniqueID.next);
|
||||||
|
var sfv;
|
||||||
|
|
||||||
if(parent_.isNil,{
|
audioBuffer.write(path,"wav");
|
||||||
xpos = 0;
|
|
||||||
ypos = 0;
|
|
||||||
win = Window("FluidWaveform",bounds);
|
|
||||||
win.background_(Color.white);
|
|
||||||
},{
|
|
||||||
xpos = bounds.left;
|
|
||||||
ypos = bounds.top;
|
|
||||||
win = parent_;
|
|
||||||
UserView(win,Rect(xpos,ypos,bounds.width,bounds.height))
|
|
||||||
.drawFunc_{
|
|
||||||
Pen.fillColor_(Color.white);
|
|
||||||
Pen.addRect(Rect(0,0,bounds.width,bounds.height));
|
|
||||||
Pen.fill;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if(imageBuffer.notNil,{
|
audioBuffer.server.sync;
|
||||||
var condition = Condition.new;
|
|
||||||
var colors;
|
|
||||||
|
|
||||||
// TODO: no need for this to be a switch statement.
|
sfv = SoundFileView(win,bounds);
|
||||||
imageColorScheme.switch(
|
sfv.peakColor_(waveformColor);
|
||||||
0,{
|
sfv.drawsBoundingLines_(false);
|
||||||
colors = this.loadColorFile("CET-L02");
|
sfv.rmsColor_(Color.clear);
|
||||||
},
|
sfv.background_(Color.clear);
|
||||||
1,{
|
sfv.readFile(SoundFile(path));
|
||||||
colors = this.loadColorFile("CET-L16");
|
sfv.gridOn_(false);
|
||||||
},
|
|
||||||
2,{
|
|
||||||
colors = this.loadColorFile("CET-L08");
|
|
||||||
},
|
|
||||||
3,{
|
|
||||||
colors = this.loadColorFile("CET-L03");
|
|
||||||
},
|
|
||||||
4,{
|
|
||||||
colors = this.loadColorFile("CET-L04");
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"% imageColorScheme: % is not valid.".format(thisMethod,imageColorScheme).warn;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
imageBuffer.loadToFloatArray(action:{
|
File.delete(path);
|
||||||
arg vals;
|
},AppClock);
|
||||||
fork({
|
^audioBuffer.server;
|
||||||
var img = Image(imageBuffer.numFrames,imageBuffer.numChannels);
|
}
|
||||||
|
}
|
||||||
colorScaling.switch(
|
|
||||||
FluidWaveform.lin,{
|
|
||||||
var minItem = vals.minItem;
|
|
||||||
vals = (vals - minItem) / (vals.maxItem - minItem);
|
|
||||||
vals = (vals * 255).asInteger;
|
|
||||||
},
|
|
||||||
FluidWaveform.log,{
|
|
||||||
vals = (vals + 1e-6).log;
|
|
||||||
vals = vals.linlin(vals.minItem,vals.maxItem,0.0,255.0).asInteger;
|
|
||||||
// vals.postln;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"% colorScaling argument % is invalid.".format(thisMethod,colorScaling).warn;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
vals.do{
|
|
||||||
arg val, index;
|
|
||||||
img.setColor(colors[val], index.div(imageBuffer.numChannels), imageBuffer.numChannels - 1 - index.mod(imageBuffer.numChannels));
|
|
||||||
};
|
|
||||||
|
|
||||||
UserView(win,Rect(xpos,ypos,bounds.width,bounds.height))
|
|
||||||
.drawFunc_{
|
|
||||||
img.drawInRect(Rect(0,0,bounds.width,bounds.height),fraction:imageAlpha);
|
|
||||||
};
|
|
||||||
|
|
||||||
condition.unhang;
|
|
||||||
},AppClock)
|
|
||||||
});
|
|
||||||
condition.hang;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(audio_buf.notNil,{
|
FluidWaveformIndicesLayer : FluidViewer {
|
||||||
var path = "%%_%_FluidWaveform.wav".format(PathName.tmp,Date.localtime.stamp,UniqueID.next);
|
var indicesBuffer, audioBuffer, color, lineWidth;
|
||||||
|
|
||||||
audio_buf.write(path,"wav");
|
*new {
|
||||||
|
arg indicesBuffer, audioBuffer, color, lineWidth = 1;
|
||||||
|
^super.new.init(indicesBuffer, audioBuffer, color, lineWidth);
|
||||||
|
}
|
||||||
|
|
||||||
audio_buf.server.sync;
|
init {
|
||||||
|
arg indicesBuffer_, audioBuffer_, color_, lineWidth_;
|
||||||
|
indicesBuffer = indicesBuffer_;
|
||||||
|
audioBuffer = audioBuffer_;
|
||||||
|
color = color_ ? Color.red;
|
||||||
|
lineWidth = lineWidth_;
|
||||||
|
}
|
||||||
|
|
||||||
sfv = SoundFileView(win,Rect(xpos,ypos,bounds.width,bounds.height));
|
draw {
|
||||||
sfv.peakColor_(waveformColor);
|
arg win, bounds;
|
||||||
// sfv.rmsColor_(Color.black);
|
|
||||||
sfv.drawsBoundingLines_(false);
|
|
||||||
sfv.rmsColor_(Color.clear);
|
|
||||||
// sfv.background_(Color.white);
|
|
||||||
sfv.background_(Color.clear);
|
|
||||||
sfv.readFile(SoundFile(path));
|
|
||||||
sfv.gridOn_(false);
|
|
||||||
|
|
||||||
File.delete(path);
|
|
||||||
});
|
|
||||||
|
|
||||||
if(slices_buf.notNil,{
|
if(audioBuffer.notNil,{
|
||||||
slices_buf.numChannels.switch(
|
fork({
|
||||||
|
indicesBuffer.numChannels.switch(
|
||||||
1,{
|
1,{
|
||||||
slices_buf.loadToFloatArray(action:{
|
indicesBuffer.loadToFloatArray(action:{
|
||||||
arg slices_fa;
|
arg slices_fa;
|
||||||
UserView(win,Rect(xpos,ypos,bounds.width,bounds.height))
|
UserView(win,bounds)
|
||||||
.drawFunc_({
|
.drawFunc_({
|
||||||
Pen.width_(lineWidth);
|
Pen.width_(lineWidth);
|
||||||
slices_fa.do{
|
slices_fa.do{
|
||||||
arg start_samp;
|
arg start_samp;
|
||||||
var x = start_samp.linlin(0,audio_buf.numFrames,0,bounds.width);
|
var x = start_samp.linlin(0,audioBuffer.numFrames,0,bounds.width);
|
||||||
Pen.line(Point(x,0),Point(x,bounds.height));
|
Pen.line(Point(x,0),Point(x,bounds.height));
|
||||||
Pen.color_(categoryColors[categoryCounter]);
|
Pen.color_(color);
|
||||||
Pen.stroke;
|
Pen.stroke;
|
||||||
};
|
};
|
||||||
categoryCounter = categoryCounter + 1;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
2,{
|
2,{
|
||||||
slices_buf.loadToFloatArray(action:{
|
indicesBuffer.loadToFloatArray(action:{
|
||||||
arg slices_fa;
|
arg slices_fa;
|
||||||
slices_fa = slices_fa.clump(2);
|
slices_fa = slices_fa.clump(2);
|
||||||
UserView(win,Rect(xpos,ypos,bounds.width,bounds.height))
|
UserView(win,bounds)
|
||||||
.drawFunc_({
|
.drawFunc_({
|
||||||
Pen.width_(lineWidth);
|
Pen.width_(lineWidth);
|
||||||
slices_fa.do{
|
slices_fa.do{
|
||||||
arg arr;
|
arg arr;
|
||||||
var start = arr[0].linlin(0,audio_buf.numFrames,0,bounds.width);
|
var start = arr[0].linlin(0,audioBuffer.numFrames,0,bounds.width);
|
||||||
var end = arr[1].linlin(0,audio_buf.numFrames,0,bounds.width);
|
var end = arr[1].linlin(0,audioBuffer.numFrames,0,bounds.width);
|
||||||
Pen.addRect(Rect(start,0,end-start,bounds.height));
|
Pen.addRect(Rect(start,0,end-start,bounds.height));
|
||||||
Pen.color_(categoryColors[categoryCounter].alpha_(0.25));
|
Pen.color_(color.alpha_(0.25));
|
||||||
Pen.fill;
|
Pen.fill;
|
||||||
};
|
};
|
||||||
categoryCounter = categoryCounter + 1;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},{
|
},{
|
||||||
"FluidWaveform - indices_buf has neither 1 nor 2 channels. Not sure what to do with this.".warn;
|
Error("% indicesBuffer must have either 1 nor 2 channels.".format(this.class)).throw;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
},AppClock);
|
||||||
|
^indicesBuffer.server;
|
||||||
|
},{
|
||||||
|
Error("% In order to display an indicesBuffer an audioBuffer must be included.".format(this.class)).throw;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidWaveformFeaturesLayer : FluidViewer {
|
||||||
|
var featuresBuffer, colors, stackFeatures, normalizeFeaturesIndependently;
|
||||||
|
|
||||||
|
*new {
|
||||||
|
arg featuresBuffer, colors, stackFeatures = false, normalizeFeaturesIndependently = true;
|
||||||
|
^super.new.init(featuresBuffer,colors,stackFeatures,normalizeFeaturesIndependently);
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
arg featuresBuffer_, colors_, stackFeatures_ = false, normalizeFeaturesIndependently_ = true;
|
||||||
|
featuresBuffer = featuresBuffer_;
|
||||||
|
normalizeFeaturesIndependently = normalizeFeaturesIndependently_;
|
||||||
|
stackFeatures = stackFeatures_;
|
||||||
|
colors = colors_ ?? {this.createCatColors};
|
||||||
|
|
||||||
|
// we'll index into it to draw, so just in case the user passed just one color, this will ensure it can be "indexed" into
|
||||||
|
if(colors.isKindOf(SequenceableCollection).not,{colors = [colors]});
|
||||||
|
}
|
||||||
|
|
||||||
|
draw {
|
||||||
|
arg win, bounds;
|
||||||
|
|
||||||
|
featuresBuffer.loadToFloatArray(action:{
|
||||||
|
arg fa;
|
||||||
|
var minVal = 0, maxVal = 0;
|
||||||
|
var stacked_height;
|
||||||
|
|
||||||
|
if(stackFeatures,{
|
||||||
|
stacked_height = bounds.height / featuresBuffer.numChannels;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(feature_buf.notNil,{
|
if(normalizeFeaturesIndependently.not,{
|
||||||
var stacked_height = bounds.height / feature_buf.numChannels;
|
minVal = fa.minItem;
|
||||||
feature_buf.loadToFloatArray(action:{
|
maxVal = fa.maxItem;
|
||||||
arg fa;
|
});
|
||||||
var minVal = 0, maxVal = 0;
|
|
||||||
|
|
||||||
if(normalizeFeaturesIndependently.not,{
|
|
||||||
minVal = fa.minItem;
|
|
||||||
maxVal = fa.maxItem;
|
|
||||||
});
|
|
||||||
|
|
||||||
fa = fa.clump(feature_buf.numChannels).flop;
|
fa = fa.clump(featuresBuffer.numChannels).flop;
|
||||||
|
|
||||||
fa.do({
|
fork({
|
||||||
arg channel, channel_i;
|
fa.do({
|
||||||
var maxy;// a lower value;
|
arg channel, channel_i;
|
||||||
var miny; // a higher value;
|
var maxy;// a lower value;
|
||||||
|
var miny;// a higher value;
|
||||||
|
|
||||||
if(stackFeatures,{
|
if(stackFeatures,{
|
||||||
miny = stacked_height * (channel_i + 1);
|
miny = stacked_height * (channel_i + 1);
|
||||||
maxy = stacked_height * channel_i;
|
maxy = stacked_height * channel_i;
|
||||||
},{
|
},{
|
||||||
miny = bounds.height;
|
miny = bounds.height;
|
||||||
maxy = 0;
|
maxy = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(normalizeFeaturesIndependently,{
|
if(normalizeFeaturesIndependently,{
|
||||||
minVal = channel.minItem;
|
minVal = channel.minItem;
|
||||||
maxVal = channel.maxItem;
|
maxVal = channel.maxItem;
|
||||||
});
|
});
|
||||||
|
|
||||||
channel = channel.resamp1(bounds.width).linlin(minVal,maxVal,miny,maxy);
|
channel = channel.resamp1(bounds.width).linlin(minVal,maxVal,miny,maxy);
|
||||||
|
|
||||||
UserView(win,Rect(xpos,ypos,bounds.width,bounds.height))
|
UserView(win,bounds)
|
||||||
.drawFunc_({
|
.drawFunc_({
|
||||||
Pen.moveTo(Point(0,channel[0]));
|
Pen.moveTo(Point(0,channel[0]));
|
||||||
channel[1..].do{
|
channel[1..].do{
|
||||||
arg val, i;
|
arg val, i;
|
||||||
Pen.lineTo(Point(i+1,val));
|
Pen.lineTo(Point(i+1,val));
|
||||||
};
|
};
|
||||||
Pen.color_(categoryColors[categoryCounter]);
|
Pen.color_(colors[channel_i % colors.size]);
|
||||||
categoryCounter = categoryCounter + 1;
|
Pen.stroke;
|
||||||
Pen.stroke;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
},AppClock);
|
||||||
|
});
|
||||||
|
^featuresBuffer.server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidWaveformImageLayer {
|
||||||
|
var imageBuffer, imageColorScheme, imageColorScaling, imageAlpha;
|
||||||
|
|
||||||
|
*new {
|
||||||
|
arg imageBuffer, imageColorScheme = 0, imageColorScaling = 0, imageAlpha = 1;
|
||||||
|
^super.new.init(imageBuffer,imageColorScheme,imageColorScaling,imageAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
arg imageBuffer_, imageColorScheme_ = 0, imageColorScaling_ = 0, imageAlpha_ = 1;
|
||||||
|
|
||||||
|
imageBuffer = imageBuffer_;
|
||||||
|
imageColorScheme = imageColorScheme_;
|
||||||
|
imageColorScaling = imageColorScaling_;
|
||||||
|
imageAlpha = imageAlpha_;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw {
|
||||||
|
arg win, bounds;
|
||||||
|
var colors;
|
||||||
|
|
||||||
|
if(imageColorScheme.isKindOf(Color),{
|
||||||
|
// "imageColorScheme is a kind of Color".postln;
|
||||||
|
colors = 256.collect{
|
||||||
|
arg i;
|
||||||
|
Color(imageColorScheme.red,imageColorScheme.green,imageColorScheme.blue,i.linlin(0,255,0.0,1.0));
|
||||||
|
};
|
||||||
|
},{
|
||||||
|
imageColorScheme.switch(
|
||||||
|
0,{
|
||||||
|
colors = this.loadColorFile("CET-L02");
|
||||||
|
},
|
||||||
|
1,{
|
||||||
|
colors = this.loadColorFile("CET-L16");
|
||||||
|
},
|
||||||
|
2,{
|
||||||
|
colors = this.loadColorFile("CET-L08");
|
||||||
|
},
|
||||||
|
3,{
|
||||||
|
colors = this.loadColorFile("CET-L03");
|
||||||
|
},
|
||||||
|
4,{
|
||||||
|
colors = this.loadColorFile("CET-L04");
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"% imageColorScheme: % is not valid.".format(thisMethod,imageColorScheme).warn;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
imageBuffer.loadToFloatArray(action:{
|
||||||
|
arg vals;
|
||||||
|
fork({
|
||||||
|
var img = Image(imageBuffer.numFrames,imageBuffer.numChannels);
|
||||||
|
|
||||||
|
imageColorScaling.switch(
|
||||||
|
FluidWaveform.lin,{
|
||||||
|
var minItem = vals.minItem;
|
||||||
|
vals = (vals - minItem) / (vals.maxItem - minItem);
|
||||||
|
vals = (vals * 255).asInteger;
|
||||||
|
},
|
||||||
|
FluidWaveform.log,{
|
||||||
|
vals = (vals + 1e-6).log;
|
||||||
|
vals = vals.linlin(vals.minItem,vals.maxItem,0.0,255.0).asInteger;
|
||||||
|
// vals.postln;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"% colorScaling argument % is invalid.".format(thisMethod,imageColorScaling).warn;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// colors.postln;
|
||||||
|
|
||||||
|
vals.do{
|
||||||
|
arg val, index;
|
||||||
|
img.setColor(colors[val], index.div(imageBuffer.numChannels), imageBuffer.numChannels - 1 - index.mod(imageBuffer.numChannels));
|
||||||
|
};
|
||||||
|
|
||||||
|
UserView(win,bounds)
|
||||||
|
.drawFunc_{
|
||||||
|
img.drawInRect(Rect(0,0,bounds.width,bounds.height),fraction:imageAlpha);
|
||||||
|
};
|
||||||
|
},AppClock);
|
||||||
|
});
|
||||||
|
^imageBuffer.server;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadColorFile {
|
||||||
|
arg filename;
|
||||||
|
^CSVFileReader.readInterpret(FluidFilesPath("../Resources/color-schemes/%.csv".format(filename))).collect{
|
||||||
|
arg row;
|
||||||
|
Color.fromArray(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidWaveform : FluidViewer {
|
||||||
|
classvar <lin = 0, <log = 1;
|
||||||
|
var <win, bounds, display_bounds, <layers;
|
||||||
|
|
||||||
|
*new {
|
||||||
|
arg audioBuffer, indicesBuffer, featuresBuffer, parent, bounds, lineWidth = 1, waveformColor, stackFeatures = false, imageBuffer, imageColorScheme = 0, imageAlpha = 1, normalizeFeaturesIndependently = true, imageColorScaling = 0;
|
||||||
|
^super.new.init(audioBuffer,indicesBuffer, featuresBuffer, parent, bounds, lineWidth, waveformColor,stackFeatures,imageBuffer,imageColorScheme,imageAlpha,normalizeFeaturesIndependently,imageColorScaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
arg audio_buf, slices_buf, feature_buf, parent_, bounds_, lineWidth = 1, waveformColor,stackFeatures = false, imageBuffer, imageColorScheme = 0, imageAlpha = 1, normalizeFeaturesIndependently = true, imageColorScaling = 0;
|
||||||
|
layers = List.new;
|
||||||
|
|
||||||
|
fork({
|
||||||
|
var plotImmediately = false;
|
||||||
|
|
||||||
|
bounds = bounds_;
|
||||||
|
|
||||||
|
waveformColor = waveformColor ? Color(*0.6.dup(3));
|
||||||
|
|
||||||
|
if(bounds.isNil && imageBuffer.notNil,{
|
||||||
|
bounds = Rect(0,0,imageBuffer.numFrames,imageBuffer.numChannels);
|
||||||
|
});
|
||||||
|
|
||||||
|
bounds = bounds ? Rect(0,0,800,200);
|
||||||
|
|
||||||
|
if(parent_.isNil,{
|
||||||
|
win = Window("FluidWaveform",bounds);
|
||||||
|
win.background_(Color.white);
|
||||||
|
display_bounds = Rect(0,0,bounds.width,bounds.height);
|
||||||
|
},{
|
||||||
|
win = parent_;
|
||||||
|
display_bounds = bounds;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(imageBuffer.notNil,{
|
||||||
|
this.addImageLayer(imageBuffer,imageColorScheme,imageColorScaling,imageAlpha);
|
||||||
|
imageBuffer.server.sync;
|
||||||
|
plotImmediately = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(audio_buf.notNil,{
|
||||||
|
this.addAudioLayer(audio_buf,waveformColor);
|
||||||
|
audio_buf.server.sync;
|
||||||
|
plotImmediately = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(feature_buf.notNil,{
|
||||||
|
this.addFeaturesLayer(feature_buf,this.createCatColors,stackFeatures,normalizeFeaturesIndependently);
|
||||||
|
feature_buf.server.sync;
|
||||||
|
plotImmediately = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(slices_buf.notNil,{
|
||||||
|
this.addIndicesLayer(slices_buf,audio_buf,Color.red,lineWidth);
|
||||||
|
slices_buf.server.sync;
|
||||||
|
plotImmediately = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(plotImmediately,{this.front;});
|
||||||
|
},AppClock);
|
||||||
|
}
|
||||||
|
|
||||||
|
addImageLayer {
|
||||||
|
arg imageBuffer, imageColorScheme = 0, imageColorScaling = 0, imageAlpha = 1;
|
||||||
|
var l = FluidWaveformImageLayer(imageBuffer,imageColorScheme,imageColorScaling,imageAlpha);
|
||||||
|
|
||||||
|
// l.postln;
|
||||||
|
layers.add(l);
|
||||||
|
// layers.postln;
|
||||||
|
// l.draw(win,display_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAudioLayer {
|
||||||
|
arg audioBuffer, waveformColor;
|
||||||
|
var l = FluidWaveformAudioLayer(audioBuffer,waveformColor);
|
||||||
|
|
||||||
|
// l.postln;
|
||||||
|
layers.add(l);
|
||||||
|
// layers.postln;
|
||||||
|
|
||||||
|
// l.draw(win,display_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
addIndicesLayer {
|
||||||
|
arg indicesBuffer, audioBuffer, color, lineWidth = 1;
|
||||||
|
var l = FluidWaveformIndicesLayer(indicesBuffer,audioBuffer,color,lineWidth);
|
||||||
|
|
||||||
|
// l.postln;
|
||||||
|
layers.add(l);
|
||||||
|
// layers.postln;
|
||||||
|
|
||||||
|
// l.draw(win,display_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
addFeaturesLayer {
|
||||||
|
arg featuresBuffer, colors, stackFeatures = false, normalizeFeaturesIndependently = true;
|
||||||
|
var l = FluidWaveformFeaturesLayer(featuresBuffer,colors,stackFeatures,normalizeFeaturesIndependently);
|
||||||
|
|
||||||
|
// l.postln;
|
||||||
|
layers.add(l);
|
||||||
|
// layers.postln;
|
||||||
|
|
||||||
|
// l.draw(win,display_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
addLayer {
|
||||||
|
arg fluidWaveformLayer;
|
||||||
|
layers.add(fluidWaveformLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
front {
|
||||||
|
fork({
|
||||||
|
|
||||||
|
UserView(win,display_bounds)
|
||||||
|
.drawFunc_{
|
||||||
|
Pen.fillColor_(Color.white);
|
||||||
|
Pen.addRect(Rect(0,0,bounds.width,bounds.height));
|
||||||
|
Pen.fill;
|
||||||
|
};
|
||||||
|
|
||||||
|
layers.do{
|
||||||
|
arg layer;
|
||||||
|
// layer.postln;
|
||||||
|
layer.draw(win,display_bounds).sync;
|
||||||
|
};
|
||||||
win.front;
|
win.front;
|
||||||
}.play(AppClock);
|
},AppClock);
|
||||||
|
}
|
||||||
|
|
||||||
|
close {
|
||||||
|
win.close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue