Skip to content

Commit

Permalink
multiple updates
Browse files Browse the repository at this point in the history
  • Loading branch information
allenloves committed Oct 4, 2017
1 parent 9876afd commit 25027fc
Show file tree
Hide file tree
Showing 12 changed files with 329 additions and 93 deletions.
46 changes: 27 additions & 19 deletions GUI.sc
Expand Up @@ -12,44 +12,51 @@

win = Window.new("Sound Descripter", Rect(140, 800, 1100, 200))
.front.alwaysOnTop_(true)
.background_(colorSet1[2])
//.background_(colorSet1[2])
.onClose_({soundfile.free; soundfile = nil; ~temp.free; ~temp = nil});

//*** Drop Area ***
drg = DragSink(win, Rect(15, 15, 700, 50))
.resize_(2)
.background_(colorSet1[1])
//.background_(colorSet1[1])
.align_(\center)
.string_("drop file here")
.action_({|obj|
//obj.string.postln;
if(obj.string.isSoundFile || triggerByInstance = true){ //using wslib
filename = filename ?? obj.string;


sfw = SoundFileView(win, Rect(15, 80, win.bounds.width-30, win.bounds.height-100))
.resize_(5).background_(colorSet1[0]).gridOn_(false)
.soundfile_(SoundFile.openRead(filename)).read(closeFile: true).refresh;
.resize_(5).gridOn_(false)
.soundfile_(SoundFile.openRead(filename)).read(closeFile: true).refresh
//.background_(Color(1,1,1))
//.background_(colorSet1[0])
;


soundfile = soundfile ?? SampleDescript(obj.string, loadToBuffer: false);
~temp = soundfile;

//*** Draw index lines ***
drw = UserView(win, sfw.bounds).resize_(5).background_(Color(0,0,0,0))
drw = UserView(win, sfw.bounds).resize_(5)
.background_(Color(0,0,0,0))
.drawFunc_({|uview|

//*** Draw SCMIR hoptime grid line***
block{|break|
var linelocation = 0;
while({linelocation < uview.bounds.width},
{
Pen.strokeColor_(Color.gray)
.moveTo(linelocation @ 0)
.lineTo(linelocation @ (uview.bounds.height))
.stroke;
linelocation = linelocation + (~temp.hoptime * uview.bounds.width / soundfile.duration);
};
)
};

// //*** Draw SCMIR hoptime grid line***
// block{|break|
// var linelocation = 0;
// while({linelocation < uview.bounds.width},
// {
// Pen.strokeColor_(Color.gray)
// .moveTo(linelocation @ 0)
// .lineTo(linelocation @ (uview.bounds.height))
// .stroke;
// linelocation = linelocation + (~temp.hoptime * uview.bounds.width / soundfile.duration);
// };
// )
// };

//** Reset Buttons **//
onsetButton.value_(0);
Expand Down Expand Up @@ -83,9 +90,10 @@
//***Draw onset***
soundfile.onsetTime.do({|otime|
var linelocation = onsetView.bounds.width * otime / soundfile.duration;
Pen.strokeColor_(Color.red)
Pen.strokeColor_(Color.white)
.moveTo(linelocation @ 0)
.lineTo(linelocation @ (onsetView.bounds.height))
.width_(4)
.stroke;
});
});
Expand Down
70 changes: 52 additions & 18 deletions SampleDescript.sc
Expand Up @@ -62,14 +62,15 @@ SampleDescript{
var <attackDur; // Attack Time
var <releaseDur; // Release Time
var <temporalCentroid; // Shorter value indicates percussive sounds, longer value indicates sustained sounds.
var <activeEnv;

// Frequency information



//parameters
//File Name, Normalize, Start Tine, Duration, Threshold for attack point, Threshold for end point, Threshold for onset, Time threshold for onset grouping.
*new {arg filename, normtype=0, start=0, dur=0, startThresh=0.01, endThresh=0.01, onsetThresh=0.5, groupingThresh = 0.32, filenameAsNote = false, loadToBuffer = false, normalize = false,server = Server.default, action;
*new {arg filename, normtype=0, start=0, dur=0, startThresh=0.01, endThresh=0.01, onsetThresh=0.5, groupingThresh = 0.32, filenameAsNote = false, loadToBuffer = false, normalize = false, server = Server.default, action;

^super.new.init(filename, normtype, start, dur, startThresh, endThresh, onsetThresh, groupingThresh, filenameAsNote, loadToBuffer, normalize, server, action);
}
Expand Down Expand Up @@ -150,15 +151,15 @@ SampleDescript{
this.findBreakPointByOnsets;
this.findPeaksByOnsets;
this.sectionRmsDataByOnset;
this.arEnv(startThresh, endThresh);
this.getActiveEnv(startThresh, endThresh);
this.getActiveData;
this.getKeynum(filenameAsNote);
this.getMFCC;

if(loadToBuffer)
{
server.waitForBoot{
this.loadToBuffer(bufferServer, action)};
this.loadToBuffer(bufferServer, action: action)};
}
{
action.value;
Expand Down Expand Up @@ -218,6 +219,7 @@ SampleDescript{
}

/*
//load sound file into buffers, and subsections into activeBuffer
loadToBuffer {arg server = Server.default, action;
var buf, startSample = 0, durSample;
var cond = Condition(false);
Expand Down Expand Up @@ -297,6 +299,22 @@ SampleDescript{
}


freeBuffer{
buffer.free;
Routine{
activeBuffer.do
{
|multipleChannelBuffer, index|
multipleChannelBuffer.do
{
|monoBuffer|
monoBuffer.free;
};
if(index == (activeBuffer.size - 1)){activeBuffer = []};
};
}.play;
}

getKeynum {arg filenameAsNote = false, pitchShift = 0;
var str=PathName(filename).fileNameWithoutExtension;
var l=str.size-1;
Expand Down Expand Up @@ -374,12 +392,18 @@ SampleDescript{

thisPeakIndex = thisPeakIndex.asInteger;


if(endTime[sectionIndex]-peakTime[sectionIndex] <= (hoptime * 20))
{pitch = pitchData[thisPeakIndex..endIndex[sectionIndex]].flop[0];
hasPitch = pitchData[thisPeakIndex..endIndex[sectionIndex]].flop[1]}
{pitch = pitchData[thisPeakIndex..thisPeakIndex + 20].flop[0];
hasPitch = pitchData[thisPeakIndex..thisPeakIndex + 20].flop[1];};
{
var pitchArray = pitchData[thisPeakIndex..endIndex[sectionIndex]].flop;
pitch = pitchArray[0];
hasPitch = pitchArray[1];
}
{
pitch = pitchData[thisPeakIndex..thisPeakIndex + 20].flop[0];
hasPitch = pitchData[thisPeakIndex..thisPeakIndex + 20].flop[1];
};


//find collections of data with pitch
pitch.do{|thisPitch, index|
if(hasPitch[index] >= 0.9)
Expand All @@ -393,10 +417,17 @@ SampleDescript{
if(pitchCollection.size == 0)
{
if(peakTime[sectionIndex]-startTime[sectionIndex] <= (hoptime * 20))
{pitch = pitchData[startIndex..thisPeakIndex[sectionIndex]].flop[0];
hasPitch = pitchData[startIndex..thisPeakIndex[sectionIndex]].flop[1]}
{pitch = pitchData[(thisPeakIndex - 20)..thisPeakIndex].flop[0];
hasPitch = pitchData[(thisPeakIndex - 20)..thisPeakIndex].flop[1];};
{
var pitchArray = pitchData[startIndex[sectionIndex]..thisPeakIndex[sectionIndex]].flop;
pitch = pitchArray[0];
hasPitch = pitchArray[1];
}
{
var pitchArray = pitchData[(thisPeakIndex - 20)..thisPeakIndex].flop;
pitch = pitchArray[0];
hasPitch = pitchArray[1];
};

pitch.do{|thisPitch, index|
if(hasPitch[index] >= 0.9)
{
Expand All @@ -405,10 +436,11 @@ SampleDescript{
};
};


//if no pitch data is collected, than use centroid data for pitch
//if there are pitch data collected, get the most occurred data for keynum
if(pitchCollection.size == 0 || pitchCollection.occurrencesArray(0.5).maxItem == 1)
{keynumFromPitchFound = keynumFromPitchFound.add(centroidData[thisPeakIndex].explin(20, 20000, 28, 103) - 12); // an octave lower to map to the range of my keyboard :p
{keynumFromPitchFound = keynumFromPitchFound.add((centroidData[thisPeakIndex] ? centroidData[centroidData.size-1]).explin(20, 20000, 28, 103) - 12); // an octave lower to map to the range of my keyboard :p
"no pitch detected, using centorid".postln;}
{keynumFromPitchFound = keynumFromPitchFound.add(pitchCollection.mostOccurredItems(0.5).mean)};
});
Expand All @@ -419,6 +451,7 @@ SampleDescript{
{keynum = Array.fill(peakIndex.size, keynumFromFileName) + pitchShift;}
{keynum = keynumFromPitchFound + pitchShift;}


}//end of getKeyNum


Expand Down Expand Up @@ -622,10 +655,11 @@ SampleDescript{


//play the sound file, using(at) to play each onset. If (at) is larger than the last onset index, it plays a random onset.
play {arg at = nil, out = 0, server, rate = 1, pan = 0, level = 1;
var buf, cond = Condition.new(false);
play {arg at = nil, out = 0, server, detune = 0, pan = 0, level = 1;
var buf, rate, cond = Condition.new(false);
server = server ? Server.default;
if(buffer == nil)
rate = 2 ** (detune / 12);
if(buffer == [])
{server.waitForBoot{this.loadToBuffer(server, action: {cond.test = true; cond.signal;})}}
{cond.test = true; cond.signal;};

Expand Down Expand Up @@ -653,7 +687,7 @@ SampleDescript{


//return an array of envelopes to represent each onsets.
activeEnv {|startThresh=0.1, endThresh=0.01|
getActiveEnv {|startThresh=0.01, endThresh=0.01|
var envArray = [];
this.arEnv(startThresh, endThresh);
rmsDataBySection.do{|thisSection, sectionIndex|
Expand All @@ -663,7 +697,7 @@ SampleDescript{
activeRmsData = rmsData[startIndex[sectionIndex]..endIndex[sectionIndex]];
envArray = envArray.add(Env.pairs([activeFrameTimes, activeRmsData].flop, \lin));
};
^envArray;
activeEnv = envArray;
}

plot {
Expand Down
68 changes: 56 additions & 12 deletions Sampler.sc
Expand Up @@ -6,6 +6,10 @@

//instance of Sampler is a database of multiple SampleDescript
Sampler {

classvar <> defaultTexture;
classvar <> defaultOutputBus = 0;

var <dbs; // an array of SamplerDB instances that this Sampler is registered to.
var <name; //Name of this sampler
var <filenames;
Expand All @@ -19,6 +23,7 @@ Sampler {
var <numActiveBuffer;
var <averageDuration;
var <averageTemporalCentroid;
var <averageMFCC;


*new{arg samplerName, dbname = \default;
Expand Down Expand Up @@ -112,8 +117,8 @@ Sampler {

//============================
//load and analyze sound files
load {arg soundfiles, server = Server.default, filenameAsKeynum = false, normalize = false, action = nil;
var averageDur, averageTmpCentroid;
load {arg soundfiles, server = Server.default, filenameAsKeynum = false, normalize = false, startThresh=0.01, endThresh=0.01, action = nil;
averageMFCC = averageMFCC ? Array.fill(13, 0);
if(soundfiles.isArray.not){Error("Sound files has to be an array").throw};
bufServer = server;
fork{
Expand All @@ -128,11 +133,13 @@ Sampler {
numActiveBuffer = numActiveBuffer + sample.activeDuration.size;
averageDuration = averageDuration + sample.activeDuration.sum;
averageTemporalCentroid = averageTemporalCentroid + sample.temporalCentroid.sum;
averageMFCC = averageMFCC + sample.mfcc.sum;
dict.put(filename.asSymbol, sample);
};

averageDuration = averageDuration / numActiveBuffer;
averageTemporalCentroid = averageTemporalCentroid / numActiveBuffer;
averageMFCC = averageMFCC / numActiveBuffer;
dict = dict.asSortedArray.flop;
filenames = dict[0];
samples = dict[1];
Expand Down Expand Up @@ -198,16 +205,27 @@ Sampler {
)
}

setThresh{|startThresh=0.01, endThresh=0.01, loadToBuffer=true|
var cond = Condition.new;
Routine{
samples.do{|sample|
sample.freeBuffer;
sample.arEnv(startThresh, endThresh);
if(loadToBuffer){sample.loadToBuffer(action: {cond.unhang})};
cond.hang;
}
}.play;
}



//========================================
//Play samples by giving key numbers
//Defaults are also provided by SamplerArguments
//Negative key numbers reverses the buffer to play.
key {arg keynums, syncmode = \keeplength, dur = nil, amp = 1, ampenv = [0, 1, 1, 1], pan = 0, panenv = [0, 0, 1, 0], bendenv = nil, texture = nil, expand = nil, grainRate = 20, grainDur = 0.15, out = 0, midiChannel = 0, play = true;
key {arg keynums, syncmode = \keeplength, dur = nil, amp = 1, ampenv = [0, 1, 1, 1], pan = 0, panenv = [0, 0, 1, 0], bendenv = nil, texture = nil, expand = nil, grainRate = 20, grainDur = 0.15, out = this.class.defaultOutputBus, midiChannel = 0, play = true;
var args = SamplerArguments.new;
var playkey = keynums ? rrand(10.0, 100.0);
var playkey = keynums ? {rrand(10.0, 100.0)};
args.set(keynums: playkey, syncmode: syncmode, dur: dur, amp: amp, ampenv: ampenv, pan: pan, panenv: panenv, bendenv: bendenv, texture: texture, expand: expand, grainRate: grainRate, grainDur: grainDur, out: out, midiChannel: midiChannel);
args.setSamples(SamplerQuery.getSamplesByKeynum(this, args)); //find play samples

Expand All @@ -216,19 +234,30 @@ Sampler {
}


//play samples by giving an array of samples to play
//the members of samplesArray contains two members: a SampleDescript object, and section index
// etc. [[SampleDescript, 2], [SampleDescript, 0], ......]
playSample {arg samplesArray, syncmode = \keeplength, detune = 0, dur = nil, amp = 1, ampenv = [0, 1, 1, 1], pan = 0, panenv = [0, 0, 1, 0], bendenv = nil, texture = nil, expand = nil, grainRate = 20, grainDur = 0.15, out = this.class.defaultOutputBus, midiChannel = 0, play = true;
var args = SamplerArguments.new;
args.set(syncmode: syncmode, detune: detune, dur: dur, amp: amp, ampenv: ampenv, pan: pan, panenv: panenv, bendenv: bendenv, texture: texture, expand: expand, grainRate: grainRate, grainDur: grainDur, out: out, midiChannel: midiChannel);

}


playArgs {|args|
this.class.playArgs(args);
}




//==============================================================
//TODO: Play a sample with the influence of a global envelope
playEnv {arg env, keynums, morph = [0, 1, \atpeak], maxtexture = 5;
var playkey = keynums ? rrand(10.0, 100.0);
playEnv {arg env, keynums, dur, amp = 1, pan = 0, maxtexture = 5, out = this.class.defaultOutputBus, midiChannel = 0;
var playkey = keynums ? {rrand(10.0, 100.0)};

case
{this.averageDuration < 0.3}
{(this.averageDuration < 0.3) || ((dur ? 1) < 0.2)}
{
Routine.run{
var elapsed = 0;
Expand All @@ -238,7 +267,7 @@ Sampler {
var texture = env.at(elapsed).linlin(0, env.levels.maxItem, 1, maxtexture).asInteger;
//args.set(syncmode: \percussive, amp: env.at(elapsed), texture: texture);
//this.playArgs(args);
this.key(keynums.asArray.choose, \percussive, amp: env.at(elapsed), texture: texture);
this.key(keynums.asArray.choose, \percussive, dur: dur, amp: env.at(elapsed) * amp, pan: pan, texture: texture, out: out, midiChannel: midiChannel);
elapsed = elapsed + delayTime;
delayTime.wait;
}
Expand All @@ -247,14 +276,29 @@ Sampler {
}
{true}
{

env.peakTime.do{|thisPeakTime|
//For Each Peak time of the envelop, put a sound peaking at that moment
env.peakTime.do{|thisPeakTime, index|
var previousPeakTime = env.peakTime[index - 1] ? 0;
var nextPeakTime = env.peakTime[index + 1] ? env.duration;
var attackTime = (thisPeakTime - previousPeakTime).abs;
var releaseTime = (nextPeakTime - thisPeakTime).abs;
var args = SamplerArguments.new;
var maxTexture, texture;
args.set(keynums: playkey.value.asArray);

//put data into args
args.set(keynums: playkey.value.asArray, out: out, midiChannel: midiChannel);
args.setSamples(SamplerQuery.getSamplesByKeynum(this, args));


if(attackTime > args.globalAttackDur){
if(args.globalAttackDur < 0.1){var keys = args.keynums; args.set(keynums: keys ++ keys.neg)};
};
if(releaseTime > args.globalReleaseDur){
if(args.globalReleaseDur < 0.1){var keys = args.keynums; args.set(keynums: keys ++ keys.neg)};
};
args.setSamples(SamplerQuery.getSamplesByKeynum(this, args));
texture = env.range.at(thisPeakTime).linlin(0, 1, 1, maxtexture).asInteger;
args.set(syncmode: [\peakat, thisPeakTime], amp: env.at(thisPeakTime), texture: texture);
args.set(syncmode: [\peakat, thisPeakTime], amp: env.at(thisPeakTime) * amp, pan: pan, texture: texture);
this.playArgs(args);
}
};
Expand Down

0 comments on commit 25027fc

Please sign in to comment.