diff --git a/release-packaging/Classes/FluidPlotter.sc b/release-packaging/Classes/FluidPlotter.sc index 0503797..7c1681a 100644 --- a/release-packaging/Classes/FluidPlotter.sc +++ b/release-packaging/Classes/FluidPlotter.sc @@ -16,8 +16,8 @@ FluidPlotterPoint { } } -FluidPlotter { - var (catColors.size-1),{ + if(category_int > (categoryColors.size-1),{ "FluidPlotter:setCategories_ FluidPlotter doesn't have that many category colors. You can use the method 'setColor_' to set colors for individual points.".warn }); - color = catColors[category_int]; + color = categoryColors[category_int]; fp_pt.color_(color); }); this.refresh; diff --git a/release-packaging/Classes/FluidWaveform.sc b/release-packaging/Classes/FluidWaveform.sc index 88934e3..2c9aa84 100644 --- a/release-packaging/Classes/FluidWaveform.sc +++ b/release-packaging/Classes/FluidWaveform.sc @@ -1,15 +1,31 @@ -FluidWaveform { +FluidViewer { + var categoryColors; + + createCatColors { + categoryColors = "1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf".clump(6).collect{ + arg six; + Color(*six.clump(2).collect{ + arg two; + "0x%".format(two).interpret / 255; + }); + }; + } +} + +FluidWaveform : FluidViewer { *new { - arg audio_buf, slices_buf, bounds; - ^super.new.init(audio_buf,slices_buf, bounds); + arg audio_buf, slices_buf, feature_buf, bounds, lineWidth = 1; + ^super.new.init(audio_buf,slices_buf, feature_buf, bounds, lineWidth); } init { - arg audio_buf, slices_buf, bounds; + arg audio_buf, slices_buf, feature_buf, bounds, lineWidth; Task{ var path = "%%_%_FluidWaveform.wav".format(PathName.tmp,Date.localtime.stamp,UniqueID.next); - var sfv, win, userView; + var sfv, win, categoryCounter = 0; + + this.createCatColors; bounds = bounds ? Rect(0,0,800,200); win = Window("FluidWaveform",bounds); @@ -18,26 +34,77 @@ FluidWaveform { audio_buf.server.sync; sfv = SoundFileView(win,Rect(0,0,bounds.width,bounds.height)); + sfv.peakColor_(Color(*0.75.dup(3))); + sfv.rmsColor_(Color.black); + sfv.background_(Color.white); sfv.readFile(SoundFile(path)); sfv.gridOn_(false); File.delete(path); if(slices_buf.notNil,{ - slices_buf.loadToFloatArray(action:{ - arg slices_fa; - - userView = UserView(win,Rect(0,0,bounds.width,bounds.height)) - .drawFunc_({ - slices_fa.do{ - arg start_samp; - var x = start_samp.linlin(0,audio_buf.numFrames,0,bounds.width); - Pen.line(Point(x,0),Point(x,bounds.height)); - Pen.color_(Color.red); + slices_buf.numChannels.switch( + 1,{ + slices_buf.loadToFloatArray(action:{ + arg slices_fa; + UserView(win,Rect(0,0,bounds.width,bounds.height)) + .drawFunc_({ + Pen.width_(lineWidth); + slices_fa.do{ + arg start_samp; + var x = start_samp.linlin(0,audio_buf.numFrames,0,bounds.width); + Pen.line(Point(x,0),Point(x,bounds.height)); + Pen.color_(categoryColors[categoryCounter]); + Pen.stroke; + }; + categoryCounter = categoryCounter + 1; + }); + }); + }, + 2,{ + slices_buf.loadToFloatArray(action:{ + arg slices_fa; + slices_fa = slices_fa.clump(2); + UserView(win,Rect(0,0,bounds.width,bounds.height)) + .drawFunc_({ + Pen.width_(lineWidth); + slices_fa.do{ + arg arr; + var start = arr[0].linlin(0,audio_buf.numFrames,0,bounds.width); + var end = arr[1].linlin(0,audio_buf.numFrames,0,bounds.width); + Pen.addRect(Rect(start,0,end-start,bounds.height)); + Pen.color_(categoryColors[categoryCounter].alpha_(0.25)); + Pen.fill; + }; + categoryCounter = categoryCounter + 1; + }); + }); + },{ + "FluidWaveform - indices_buf has neither 1 nor 2 channels. Not sure what to do with this.".warn; + } + ); + }); + + if(feature_buf.notNil,{ + feature_buf.loadToFloatArray(action:{ + arg fa; + fa = fa.clump(feature_buf.numChannels).flop; + fa.do({ + arg channel; + channel = channel.resamp1(bounds.width).linlin(channel.minItem,channel.maxItem,bounds.height,0); + UserView(win,Rect(0,0,bounds.width,bounds.height)) + .drawFunc_({ + Pen.moveTo(Point(0,channel[0])); + channel[1..].do{ + arg val, i; + Pen.lineTo(Point(i+1,val)); + }; + Pen.color_(categoryColors[categoryCounter]); + categoryCounter = categoryCounter + 1; Pen.stroke; - }; + }); }); - }); + }) }); win.front; diff --git a/release-packaging/HelpSource/Classes/FluidWaveform.schelp b/release-packaging/HelpSource/Classes/FluidWaveform.schelp index 6979245..3545fc3 100644 --- a/release-packaging/HelpSource/Classes/FluidWaveform.schelp +++ b/release-packaging/HelpSource/Classes/FluidWaveform.schelp @@ -29,6 +29,7 @@ EXAMPLES:: code:: +s.boot; // load a sound to slice ~drums = Buffer.read(s,File.realpath(FluidBufAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); @@ -39,5 +40,24 @@ code:: FluidBufAmpSlice.process(s,~drums,indices:~indices,fastRampUp: 10,fastRampDown: 2205,slowRampUp: 4410,slowRampDown: 4410,onThreshold: 10,offThreshold: 5,floor: -40,minSliceLength: 4410,highPassFreq: 20); // plot the buffer with the indices overlayed -FluidWaveform(~drums,~indices,Rect(0,0,800,200)); +FluidWaveform(~drums,~indices,nil,Rect(0,0,800,200)); + +// do a descriptor analysis +~features = Buffer(s); +FluidBufLoudness.process(s,~drums,features:~features,action:{"done".postln;}); + +// copy just the first channel of that buffer to display it +~features2 = Buffer(s); +FluidBufCompose.process(s,~features,numChans:1,destination:~features2); + +// plot the audio with the slices and the loudness analysis +FluidWaveform(~drums,~indices,~features2,Rect(0,0,1200,300)); + +// with gate info +~gate_analysis = Buffer(s); +FluidBufAmpGate.process(s,~drums,indices:~gate_analysis,onThreshold:-35,offThreshold:-35,minSliceLength:4410); + +// it will plot the ons and offs +FluidWaveform(~drums,~gate_analysis,~features2,Rect(0,0,1200,300)); + ::