Greetings,
I revisited this to take a look at PA’s main suggestion, which was to do the analysis JIT style by filling a buffer and then analyzing it all at once. It ended up not working out. I ran into a couple bottlenecks / design considerations.
- The first is that it’s actually quite elegant to have the analysis vector created on the server in one place, and then used both to populate the dataset, but also to do the classification. If one wants to create the analysis vectors for the dataset from the buffer, it would require hard coding in both places what parameters are in the vector. Also, if one wanted to use multiple Fluid analyses for their database vector (FluidMFCC & FluidSpectralShape for example), one would have to “analyze” the buffer twice, once with FluidBufMFCC and again with FluidBufSpectralShape, and then concatenate those vectors. It seems simpler to keep the analysis vector creation on the server.
- Is there a way to initialize the number of entries in a FluidDataSet? For example, I want a new FluidDataSet on server “s”, named \teds_data, with dimensionality 13, and 600 entries: FluidDataSet(s,\teds_data,13,600). The reason I ask is that I find myself doing this thing:
if(i_have_the_num_entries_i_need,{
dataset.updatePoint(i.asString,vector);
},{
dataset.addPoint(i.asString,vector);
})
This way, I’m overwriting data points (filling it up like a circle buffer), but I can only do the overwriting if it’s the proper size (proper number of entries). If I could initialize the size, then I could just use updatePoint.
I realize I could do this manually at the outset right after creation:
n_points_i_want.do({
arg i;
dataset.addPoint(i.asString,0.dup(nb_of_dims));
});
Just wondering if it would be an easy feature to add (also might be useful to know for memory allocation?).
- The next issue I encountered was that once I did the FluidBufMFCC and got the features buffer back (which is very quick), it then took quite a long time to get that data into a FluidDataSet so that I could then use FluidKMeans. The process of taking the frame out of the FluidBufMFCC features buffer and getting it into it’s own buffer so that I could use that to update it in the dataset, is too slow to be useful (to use in real-time applications). So I think for this reason and for #1 above, the best approach is the initial one–to add (or overwrite) vectors in the database as the come off the server with SendReply–and to also use that SendReply as the source of the vectors for the classification.
- Lastly, my FluidKMeans seems to be crashing the server on .fit, but not every time. I haven’t isolated it more, but I’m posting the code here and the crash report.
// if you highlight all and cmd-return, it should run...
(
s.waitForBoot({
Task({
var updatePeriod = 5 /*in seconds*/; // how often to recompute the k means
// how long into the past should we keep track of for clustering into k means
var totalHistory = 10 /*in seconds*/;
var circBuf = Buffer.alloc(s,totalHistory * s.sampleRate);
var bus = Bus.audio(s); // for sending audio to the analysis synth
var synth; // plays a buffer
var analysis_synth; // does analysis
var trigRate = 30; // how many times to update every second
// audio input - put your sound file here (or route different incoming audio to the analysis synth)
var audioBuf = Buffer.read(s,"/Users/ted/Documents/_CREATING/_PROJECT FILES/Machine Learning/Training Data/Audio/source audio/ml examples/elec/stereos/no_input_mixer 01.wav");
//var audioBuf = Buffer.read(s,"/Users/Ted/Music/ml test files/saxophone 01.wav");
// keep track of how many frames have been processed so we know when we have enough data to run the k means
var frameCounter = 0;
var nb_of_dims = 12; // just the 12 mfccs for now...
var dataset = FluidDataSet(s,\raw_data,nb_of_dims);
var normed_dataset = FluidDataSet(s,\normed_dataset,nb_of_dims);
var scaler = FluidNormalize(s);
//var ranges = ControlSpec(inf,-inf).dup(nb_of_dims);
var assimilate_point; // a function that normalizes the incoming points with historical extremes
var kmeans = FluidKMeans(s);
var k_ = 4; // what the k will be for k means
var get_cluster; // a function that will take in a buffer (vector) update the view with it's color
var nHistories = trigRate * totalHistory; // total number of histories to keep track of
var updateBuf = Buffer.alloc(s,nb_of_dims); // a buffer to use for sending new points to the FluidDataSet
var updateBuf2 = Buffer.alloc(s,nb_of_dims);
var normedBuf = Buffer.alloc(s,nb_of_dims);
var features = Buffer(s);
var clustered = false; // is true once at least one clustering has happened (at one point one can predict on new points)
var buffer_filled = false; // is true once we have saved 'nHistories' vectors to the FluidDataSet
var uvs; // userviews that will flash showing current cluster prediction
var win; // window where the colors flash
// the colors that flash (4 for now because 'k_' = 4, would need more with a larger k)
var colors = [Color.cyan,Color.yellow,Color.green,Color.red];
s.sync;
// play sound
synth = {
arg rate = 0;
var sig = PlayBuf.ar(audioBuf.numChannels,audioBuf,rate,loop:1);
//var sig = SoundIn.ar(0);
Out.ar(bus,Mix(sig));
sig * -20.dbamp;
}.play;
s.sync;
// define this function that will take in a buffer (vector) update the view with it's color
get_cluster = {
arg unnormed_buf;
scaler.normalizePoint(unnormed_buf,normedBuf,{
kmeans.predictPoint(normedBuf,{
arg cluster;
/* cluster.postln;
"".postln;*/
uvs.do({
arg uv, i;
if(cluster == i,{
defer{
//uv.visible_(true)
// using alpha here because it might be nice to set the alpha to the
// amplitude or something so it flickers with the sound...
uv.background_(uv.background.alpha_(1));
};
},{
defer{
//uv.visible_(false);
// alpha = 0 means don't show me this.
uv.background_(uv.background.alpha_(0));
};
})
});
});
});
};
// synth that does the analysis and sends the vector back to the language
analysis_synth = {
arg in_bus;
var input = In.ar(in_bus);
// ------------------ original approach ---------------------
// --------- (still need this to send real time vectors to lang) -----------------
// put in whatever kind of analysis you want
var vector = FluidMFCC.kr(input); // 13 by default
vector = vector[1..12];
//KMeansRT.kr(kmeansrtBuf,vector,k_,1,0,1).poll;
SendReply.kr(Impulse.kr(trigRate),"/analysis_vector",vector);
// ---------- jit circle buf approach as suggested by pa -------------
RecordBuf.ar(input,circBuf);
Silence.ar;
}.play(synth,addAction:\addAfter,args:[\in_bus,bus]);
// the vectors are sent from the server to here:
OSCFunc({
arg msg;
var vec = msg[3..14]; // take only the 12 mfccs for now
//vec.postln;
// ----------------------- original approach --------------------------
/* // load the vector to the server
updateBuf.loadCollection(vec,0,{
//arg buf;
//"buffer to update: %".format(updateBuf).postln;
if(buffer_filled,{ // if we have already put 'nHistories' points in the FluidDataSet, then...
// update it
dataset.updatePoint(frameCounter.asString,updateBuf,{
// only if at least one prediction has happened, make a prediction!
if(clustered,{
get_cluster.(updateBuf);
});
});
},{
// if not, then, add it
dataset.addPoint(frameCounter.asString,updateBuf,{
// only if at least one prediction has happened, make a prediction!
if(clustered,{
get_cluster.(updateBuf);
});
});
});
// modulo the frameCounter
frameCounter = (frameCounter + 1) % nHistories;
// if we've adding 'nHistories' points, set the flag
if(frameCounter == (nHistories - 1),{buffer_filled = true;});
});*/
// updateBuf2.loadCollection(vec,0,{
// if(clustered,{
// get_cluster.(updateBuf2);
// });
// });
if(clustered,{
Routine({
updateBuf2.setn(0,vec);
s.sync;
get_cluster.(updateBuf2);
}).play;
});
},"/analysis_vector");
// kind of cheeky, but the synth doesnt play the sound until everything is in place...
synth.set(\rate,1);
// for all of time, fit the k means to the dataset, but wait 'updatePeriod' in between (default is 10 sec)
Task({
// wait for the whole circle buffer to fill up!
totalHistory.wait;
inf.do({
arg i;
i.postln;
// ------------- original approach
/* scaler.fit(dataset.asString,{
scaler.normalize(dataset.asString,normed_dataset.asString,{
kmeans.fit(normed_dataset,k_,500,action:{
//"clustering done".postln;
clustered = true;
});
});
});*/
// get the mfcc features
FluidBufMFCC.process(s,circBuf,features:features,action:{
features.postln;
// load the features into the dataset;
features.numFrames.do({
arg frame_i;
"frame i: %".format(frame_i).postln;
//features.copyData(updateBuf,(frame_i * features.numChannels) + 1,0,nb_of_dims);
features.loadToFloatArray((frame_i * features.numChannels) + 1,nb_of_dims,{
arg float_array;
/* updateBuf.loadCollection(float_array,0,{
if(i == 0,{ // if this is the first time, add a point, otherwise, update
dataset.addPoint(frame_i.asString,updateBuf);
},{
dataset.updatePoint(frame_i.asString,updateBuf);
});
});*/
updateBuf.setn(0,float_array);
s.sync;
if(i == 0,{ // if this is the first time, add a point, otherwise, update
dataset.addPoint(frame_i.asString,updateBuf);
},{
dataset.updatePoint(frame_i.asString,updateBuf);
});
});
});
// normalize the dataset
scaler.fit(dataset.asString,{
scaler.normalize(dataset.asString,normed_dataset.asString,{
kmeans.fit(normed_dataset,k_,500,action:{
"clustering done".postln;
clustered = true;
});
});
});
});
updatePeriod.wait;
});
},AppClock).play;
// window for showing the current cluster prediction
Window.closeAll;
win = Window("",Rect(Window.screenBounds.width + 100,100,600,800)).front;
win.background_(Color.black);
uvs = k_.collect({
arg i;
var width = win.bounds.width / k_;
var uv = UserView(win,Rect(width * i,0,width,win.bounds.height));
uv.background_(colors[i].alpha_(0));
//uv.visible_(false);
});
},AppClock).play;
});
)
Process: coreaudiod [236]
Path: /usr/sbin/coreaudiod
Identifier: coreaudiod
Version: 5.0 (5.0)
Code Type: X86-64 (Native)
Parent Process: launchd [1]
Responsible: coreaudiod [236]
User ID: 202
PlugIn Path: /Library/Audio/Plug-Ins/HAL/BlackHole.driver/Contents/MacOS/BlackHole
PlugIn Identifier: audio.existential.BlackHole
PlugIn Version: 0.2.6 (1)
Date/Time: 2020-04-05 15:04:52.800 -0400
OS Version: Mac OS X 10.15.4 (19E266)
Report Version: 12
Bridge OS Version: 3.0 (14Y908)
Anonymous UUID: 725D907C-009E-FB2F-BA7A-3FC2D83702A3
Sleep/Wake UUID: 338BDEC6-7350-46C9-978F-08FF761DEBBE
Time Awake Since Boot: 130000 seconds
Time Since Wake: 52000 seconds
System Integrity Protection: enabled
Crashed Thread: 7 audio IO: BlackHole_UID
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x00000001056fc000
Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Bus error: 10
Termination Reason: Namespace SIGNAL, Code 0xa
Terminating Process: exc handler [236]
VM Regions Near 0x1056fc000:
MALLOC_LARGE 000000010567c000-00000001056fc000 [ 512K] rw-/rwx SM=PRV
–> VM_ALLOCATE 00000001056fc000-00000001056fd000 [ 4K] r–/rwx SM=PRV
VM_ALLOCATE 00000001056fd000-00000001057fd000 [ 1024K] rw-/rwx SM=PRV
Application Specific Information:
dyld3 mode
Thread 0:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x00007fff6a2cedfa mach_msg_trap + 10
1 libsystem_kernel.dylib 0x00007fff6a2cf170 mach_msg + 60
2 com.apple.CoreFoundation 0x00007fff302460b5 __CFRunLoopServiceMachPort + 247
3 com.apple.CoreFoundation 0x00007fff30244b82 __CFRunLoopRun + 1319
4 com.apple.CoreFoundation 0x00007fff30243ffe CFRunLoopRunSpecific + 462
5 coreaudiod 0x0000000101c14c29 main + 5308
6 libdyld.dylib 0x00007fff6a18dcc9 start + 1
Thread 1:: AMCP Logging Spool
0 libsystem_kernel.dylib 0x00007fff6a2cee36 semaphore_wait_trap + 10
1 com.apple.audio.caulk 0x00007fff63d67b16 caulk::mach::semaphore::wait() + 16
2 com.apple.audio.caulk 0x00007fff63d679b2 caulk::semaphore::timed_wait(double) + 106
3 com.apple.audio.caulk 0x00007fff63d677c4 caulk::concurrent::details::worker_thread::run() + 30
4 com.apple.audio.caulk 0x00007fff63d671e4 void* caulk::thread_proxy<std::__1::tuple<caulk::attributes, void (caulk::concurrent::details::worker_thread::)(), std::__1::tuplecaulk::concurrent::details::worker_thread* > >(void) + 45
5 libsystem_pthread.dylib 0x00007fff6a392109 _pthread_start + 148
6 libsystem_pthread.dylib 0x00007fff6a38db8b thread_start + 15
Thread 2:
0 libsystem_kernel.dylib 0x00007fff6a2cee36 semaphore_wait_trap + 10
1 com.apple.audio.caulk 0x00007fff63d67b16 caulk::mach::semaphore::wait() + 16
2 com.apple.audio.caulk 0x00007fff63d679b2 caulk::semaphore::timed_wait(double) + 106
3 com.apple.audio.caulk 0x00007fff63d677c4 caulk::concurrent::details::worker_thread::run() + 30
4 com.apple.audio.caulk 0x00007fff63d671e4 void* caulk::thread_proxy<std::__1::tuple<caulk::attributes, void (caulk::concurrent::details::worker_thread::)(), std::__1::tuplecaulk::concurrent::details::worker_thread* > >(void) + 45
5 libsystem_pthread.dylib 0x00007fff6a392109 _pthread_start + 148
6 libsystem_pthread.dylib 0x00007fff6a38db8b thread_start + 15
Thread 3:: HAL Async Logger
0 libsystem_kernel.dylib 0x00007fff6a2cee36 semaphore_wait_trap + 10
1 com.apple.audio.CoreAudio 0x00007fff2f77908a ca::mach::semaphore::wait() + 16
2 com.apple.audio.CoreAudio 0x00007fff2fa688ce ca::concurrent::details::worker_thread::run(ca::attributes) + 390
3 com.apple.audio.CoreAudio 0x00007fff2fa689fd void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct >, void (ca::concurrent::details::worker_thread::)(ca::attributes), ca::concurrent::details::worker_thread, ca::attributes> >(void*) + 188
4 libsystem_pthread.dylib 0x00007fff6a392109 _pthread_start + 148
5 libsystem_pthread.dylib 0x00007fff6a38db8b thread_start + 15
Thread 4:: Audio HAL Overload Reporting Spool
0 libsystem_kernel.dylib 0x00007fff6a2cee36 semaphore_wait_trap + 10
1 com.apple.audio.CoreAudio 0x00007fff2f77908a ca::mach::semaphore::wait() + 16
2 com.apple.audio.CoreAudio 0x00007fff2fa688ce ca::concurrent::details::worker_thread::run(ca::attributes) + 390
3 com.apple.audio.CoreAudio 0x00007fff2fa689fd void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct >, void (ca::concurrent::details::worker_thread::)(ca::attributes), ca::concurrent::details::worker_thread, ca::attributes> >(void*) + 188
4 libsystem_pthread.dylib 0x00007fff6a392109 _pthread_start + 148
5 libsystem_pthread.dylib 0x00007fff6a38db8b thread_start + 15
Thread 5:
0 libsystem_kernel.dylib 0x00007fff6a2d70fe __select + 10
1 com.zerodebug.audiomux 0x0000000101f8bffd LocalClient::Work() + 1581
2 com.zerodebug.audiomux 0x0000000101f95dae client_thread_proc(void*) + 14
3 libsystem_pthread.dylib 0x00007fff6a392109 _pthread_start + 148
4 libsystem_pthread.dylib 0x00007fff6a38db8b thread_start + 15
Thread 6:
0 libsystem_pthread.dylib 0x00007fff6a38db68 start_wqthread + 0
Thread 7 Crashed:: audio IO: BlackHole_UID
0 libsystem_platform.dylib 0x00007fff6a383dc9 _platform_bzero$VARIANT$Haswell + 41
1 audio.existential.BlackHole 0x0000000101ed2f47 BlackHole_DoIOOperation + 759
2 com.apple.audio.CoreAudio 0x00007fff2fb1182f HALS_PlugInEngine::_ReadFromStream_Read(HALS_IOEngine2_IOContextInfo&, HALS_IOEngine2_StreamInfo&, AudioServerPlugInIOCycleInfo const&, unsigned int, void*) + 91
3 com.apple.audio.CoreAudio 0x00007fff2fa1dbbf HALS_IOEngine2::_ReadFromStream(HALS_IOContext*, unsigned int, unsigned int, HALS_IOEngineInfo const&, unsigned int, void*) + 869
4 com.apple.audio.CoreAudio 0x00007fff2fb11740 HALS_PlugInEngine::_ReadFromStream(HALS_IOContext*, unsigned int, unsigned int, HALS_IOEngineInfo const&, unsigned int, void*) + 54
5 com.apple.audio.CoreAudio 0x00007fff2fa21599 invocation function for block in HALS_IOEngine2::ReadFromStream(HALS_IOContext*, unsigned int, unsigned int, HALS_IOEngineInfo const&, unsigned int, void*) + 678
6 com.apple.audio.CoreAudio 0x00007fff2fa6d6a4 HALB_CommandGate::ExecuteCommand(void () block_pointer) const + 98
7 com.apple.audio.CoreAudio 0x00007fff2fa1b316 HALS_IOEngine2::ReadFromStream(HALS_IOContext*, unsigned int, unsigned int, HALS_IOEngineInfo const&, unsigned int, void*) + 138
8 com.apple.audio.CoreAudio 0x00007fff2f9f51b6 HALS_IOContext::PerformIO_ReadFromStream(void*, unsigned int, HALS_IOStreamInfo&, unsigned int) + 86
9 com.apple.audio.CoreAudio 0x00007fff2f9ef268 std::__1::function<int (void*, unsigned int, HALS_IOStreamInfo&, unsigned int)>::operator()(void*, unsigned int, HALS_IOStreamInfo&, unsigned int) const + 42
10 com.apple.audio.CoreAudio 0x00007fff2f9f55ab std::__1::function<int (unsigned int, HALS_IOStreamInfo&, unsigned int)>::operator()(unsigned int, HALS_IOStreamInfo&, unsigned int) const + 37
11 com.apple.audio.CoreAudio 0x00007fff2f9f3d2c HALS_IOContext::PerformIO(AudioTimeStamp const&, unsigned int, int, unsigned int) + 968
12 com.apple.audio.CoreAudio 0x00007fff2f9f29b0 HALS_IOContext::IOThreadEntry(void*) + 9536
13 com.apple.audio.CoreAudio 0x00007fff2f9f03bf invocation function for block in HALS_IOContext::HALS_IOContext(HALS_System*, HALS_Client*, HALS_System::PowerState) + 13
14 com.apple.audio.CoreAudio 0x00007fff2f95ec22 HALB_IOThread::Entry(void*) + 72
15 libsystem_pthread.dylib 0x00007fff6a392109 _pthread_start + 148
16 libsystem_pthread.dylib 0x00007fff6a38db8b thread_start + 15
Thread 7 crashed with X86 Thread State (64-bit):
rax: 0x0000000000000000 rbx: 0x0000700001804540 rcx: 0x0000000000050900 rdx: 0x000000010567c000
rdi: 0x00000001056fc000 rsi: 0x0000000000000000 rbp: 0x0000700001804410 rsp: 0x0000700001804410
r8: 0x0000000072656164 r9: 0x00000000000035ec r10: 0x00000001058fd000 r11: 0x0000000000287600
r12: 0x00007fbbbbb1eb30 r13: 0x00007fbbbbb13200 r14: 0x00007a3c59b29cd8 r15: 0x00007fbbbbb13cd0
rip: 0x00007fff6a383dc9 rfl: 0x0000000000010206 cr2: 0x00000001056fc000
Logical CPU: 2
Error Code: 0x00000007 (invalid protections for user data write)
Trap Number: 14