karma~ (sampler/looper external)


    karma~ is a looper/sampler external for Max. It is a dynamic length, varispeed looper with some complex features that are explained in detail in the accompanying help file.
    Here is a tutorial video showing some of what karma~ can do:
    The feature set and functionality was something I conceived (and implemented a cruder version of) in The Party Van. The karma~ external has the same core functionality but super charged, lean & mean, and elegant as shit. karma~ was lovingly coded by raja, and I can't thank him enough for taking the project on!
    You can download the compiled object (for 32/64bit Mac and 32/64bit Win) as well as the source code here (1.0).
    You can follow the github repo here : https://github.com/rconstanzo/karma
    The linear interpolation used in the recording stage of karma~ is based on ipoke~ by Pierre Alexandre Tremblay.

    • May 16 2015 | 4:41 pm
      love it!
    • May 17 2015 | 4:48 am
      this is very good
    • May 18 2015 | 8:22 am
      Snap, for some reason the video didn't embed right in the post. Be sure to watch the tutorial video as it's worth watching independent of it being a tutorial video.
    • May 18 2015 | 9:30 am
    • May 18 2015 | 2:50 pm
      I edited it to show correctly, the original post didnt work.
    • May 27 2015 | 1:30 pm
      really enjoyed the tutorial video... look forward to playing with the external.
    • Jun 19 2015 | 10:39 pm
      hahaha great. I love it.
    • Sep 19 2015 | 10:47 pm
      This looks incredible!
      Though, I am having some trouble opening the .mxo file. Am I missing something?
      Trying to open .mxo file from B version, on mac running OS 10.9.5 with Max 6.1.8 32 bit
      Max opens, but no Karma!
      P.S. As far as tutorials go, you're killing it!
    • Sep 20 2015 | 3:20 am
      Ok, got it. Excuse me, I am an idiot.
    • Sep 20 2015 | 11:08 am
      Glad you found it!
    • Sep 20 2015 | 8:39 pm
      how did you open it?
    • Sep 20 2015 | 9:33 pm
      Open the helpfile that comes with it. karma~.maxhelp
      You should put karma~ itself (the mxo/mxe) into wherever you put any other externals.
    • Dec 13 2015 | 8:38 am
      I've been experimenting with Karma 1.0
      It works great!
      However, I noticed that my playing comes back delayed... in other words, it doesn't sound like the recordings are being compensated.
      Are there any plans to add delay compensation into it?
      Larry
    • Dec 13 2015 | 10:28 am
      There shouldn't be any delay in karma~ at all, as it doesn't deal with real-time audio passthrough, but if you're experiencing latency in general, externals themselves don't handle any of this kind of thing. This would be something in your "Performance and Scheduler" settings in Max. Try putting the I/O Vector and Signal Vector sizes to something smaller (256/128 ir a good middle ground).
    • Dec 13 2015 | 10:33 am
      Thank you for your quick reply.
      i have Max set to 128 samples and 64 vector.
      So, I'm not sure why I'm getting the delay.
      It's small ... 7 - 10 ms but that is a very large amount when you're dealing with quick passages in music.
      I'll see if I can figure out what it's coming from.
      Thanks!
      L
    • Dec 13 2015 | 10:42 am
      Are you getting a delay from karma's audio, or in Max in general?
      If the delay is happening when you're triggering karma you can also try having the scheduler in Overdrive (or even Audio Interrupt), as that will put the triggering in a higher priority thread.
    • Dec 13 2015 | 11:20 am
      I'm getting a delay in playback later than what I play into Karma.
      For instance, I play loop 1 into karma... establishing a rhythmic loop in tempo for about 30 seconds This loop continues and cycles just fine. I then overdub (hit record again) and add another part on top of the original part (also rhythmic).
      When I play the overdub into Karma part everything sounds in time.
      But when Karma cycles back around and plays my overdub back to me, it's several milliseconds BEHIND where I originally played it.
      That's what I'm experiencing anyway.
      I'm using an RME interface and latency is set very low.
      Overdrive is on and I've ruled out a triggering problem since it's the overdubs that are not coming back in time.
      The overdubs are played several milliseconds BEHIND where I played them into Karma originally.
      In other words, it sounds right when I play it INTO Karma, but when Karma plays it back, it's late!
      L
    • Dec 13 2015 | 11:45 am
      Hmm, not seen or experienced that. Can you make a short audio recording (or screencap) showing the problem?
    • Dec 13 2015 | 7:22 pm
      Yes, I will do that later this evening. I'm Hawaii Standard time so apparently I am several hours behind you.
      L
    • Jun 22 2016 | 9:33 am
      Wow the video tutorial is so fun and creative.
    • Jun 22 2016 | 9:46 am
      This is a brilliant object. One quick question - i had a loop running via wave~, driven by a phasor. The phasor triggered a bang that starts karma recording the loop. The recording is (very) marignally out of sync (just enough that when i jump to logical divisions, it is slightly off the beat). What is the most solid way to sync a loop with the record? If theres no other way, i can just manually nudge the timing myself. Any ideas?
    • Jun 22 2016 | 11:54 am
      Since karma~ takes messages as input it can't be driven in a sample-accurate way (hence the drift you're experiencing).
      One of planned updates for karma~ is to add a sync/phasor output (ala groove~) so karma~ could be used to drive other objects in a sample-accurate way.
    • Jun 28 2016 | 9:00 pm
      I have to say that it is great that somebody tries to keep "Looping" in max alive. Attempts to make looping easier have wanished since frip and specially xsample objects. Being very helpful for unexperienced users, frip or karma approach lack the basis of looping which for me in first place are latency compensation, so that what you overdub comes out exactly on same position in loop where you played it, and not less important recording crossfade (not just fade in/out) on record start/end. That is a must have for any serious live looping. All funky stuff with reverse, speed pitch slice upsidedown etc can be put on top if it, but if the basics are not there...
    • Jun 28 2016 | 9:11 pm
      Do you mean that what you overdub isn't what you hear back?
      I've not done hard tests on this, but it always sounded fine when playing back. Will have a closer look at this.
      Do you hear any dropouts at the start/end? If I record something continuous across the "end" of the loop it sounds fine wrapping around back to the start.
    • Jun 28 2016 | 9:31 pm
      Please don't get me wrong, critisizing is not my intention. It is that I find it sooooo great that You are doing all this work, but some so important things are missing. Latency : The fact is that one would have to offset the Playback by i/o latency amount to be able to do precise overdubbing. For many players 5 - 10 ms Latency plays no role, but for fast rhytmic patterns it really does. With crossfade I mean : connect cycle~ to karma~ input and record it. You will hear what I mean. Perfect loop will sustain so that one can't tell where loop start is.
    • Jun 28 2016 | 9:45 pm
      I use to fix latency by having main sample count run recording part straight, but playback part x samples in advance. (or loop size - x samps when reversing) So You allways hear loop playback latency compensated. The crossfade part is also easy : fade in at recording start, fade out at recording end but recording continues from loop beginning by fade length, so that one has perfect crossfade. Length can be adjustable, depending on instrument, or rhythmic content in the loop. ------
    • Jun 29 2016 | 10:18 am
      Ah I understand what you mean now.
      That's good to know actually and I've made note of those ideas in the GitHub issue tracker.
    • Aug 17 2016 | 4:39 pm
      Hi all and Rodrigo, i'm back doin' some work on M4Live and a device using karma~. If i try to "replace" a buffer wich karma~ is referring to i get this error in Max Window
      buffer~ can't read file now
      this happens even if karma~ is stopped.
      thanks a.
    • Aug 17 2016 | 4:44 pm
      Is this with 32 (b) or 64?
      Maybe it has something to do with M4L as in Max(7) I can even 'replace' the buffer while karma~ is playing back.
    • Aug 17 2016 | 6:05 pm
      Hi Rodrigo, i'm working with Windows 64 bit and Max 7 64 bit last version. karma~ does not let me replace the buffer both in Max and in M4L. karma~(b) (wich i have now compiled for win32/64 let me replace the baffer in Max but not in M4L where i have the same error 'buffer~ can't read file now.
      a.
    • Aug 17 2016 | 7:05 pm
      That narrows it down some.
      Without a Windows/M4L setup it will be hard to test/troubleshoot stuff, but I'll add the issue to the github and will take a look at it for any upcoming updates.
    • Aug 17 2016 | 7:07 pm
      Does the [set] message work alright?
    • Aug 17 2016 | 9:06 pm
      Do you mean a [set] message sent to the [buffer~] object? As far as I remember it just change the buffer reference name...
    • Aug 17 2016 | 9:37 pm
      I meant to karma~. It's not elegant, but you can just have a bunch of separate buffers with the audio files you plan on using, ready to go, and then [set bufferName] to karma~ to change the referenced buffer.
      Or a slightly more useful, but clunkier fix might be to keep a dummy buffer which you: 1)[set dummyBuffer] to karma~ 2)[replace] your "real" buffer 3)[set realBuffer] to karma~
    • Aug 18 2016 | 2:54 am
      @Alfonso This was a simple and (stupid, on my part) mistake in the code, which you might be able to fix yourself if you're able to compile code for yourself:
      simply add the line:buffer_unlocksamples(buf); in between the following lines:
      if (dirt) { buffer_setdirty(buf); }  //notify other buf-related objs...
       if (x->clockgo) { clock_delay(x->tclock, 0); x->clockgo = 0; }//list...
      found at the end of each perform routine. so that it looks like this when you're done:
       if (dirt) { buffer_setdirty(buf); }  //notify other buf-related objs...
          buffer_unlocksamples(buf);
          if (x->clockgo) { clock_delay(x->tclock, 0); x->clockgo = 0; } //list...
      then recompile and you should be good to go.
      (Everytime you have a line like this: "float *b = buffer_locksamples(buf);" there's supposed to be a matching "buffer_unlocksamples(buf);" line near the end after the perform routine is done doing it's thing, but i was an idiot for missing that :p)
      My apologies, was an oversight when making the 64bit version.
      (I was working on an update recently(found this error and fixed it in my code and was able to confirm that this worked for the 64-bit version), but then got caught up in some other business once again before i was able to finish the rest of the updates, so although i could say i'm halfway done with a newer version of karma~, it might not be ready for release until end of this year, or beginning of next.... so, since i know you're familiar with the basics of coding these externals, perhaps you can do that much for yourself, just for now, and hopefully the next incremental will be out soon.) (The equivalent for 32-bit was this: "if (dirt) { object_method((t_object *)buf, gensym("dirty")); ATOMIC_DECREMENT(&buf->b_inuse); } //notify other buf-related objs..." but that's already in the 32-bit code, so if that's not working already in M4L, i'm clueless as i'm a bit out of practice these days and can't test M4L anyways).
      If you still have problems(after making the changes in the fully 64-bit one as recommended above), it may have to wait(i've been extra busy and will be crazy-swamped until around mid-October or a bit later). Anyways, at least for the fully 64-bit version, try what i wrote, hope that helps, and sorry again for the inconvenience.
      (@Rodrigo, hope you don't mind me just writing/exposing this here... very 'unprofessional' of me, but hey, it's free! ;D )
    • Aug 18 2016 | 10:38 am
      @raja Ah glad it was a known/fixable issue and not something that needed to get hunted down on a Windows/M4L setup.
      And no worries exposing anything, I've been quite excited about it, so it's been harder not mentioning anything, hehe.
    • Aug 18 2016 | 10:41 am
      @R∑N∑G∆D∑ R∆J∆, thank you man! i've just compiled karma with the additions you suggested. It works fine in Max. I'll go check in the next minutes/hour if it works in M4L. Let me know if you guys need that i upload the compiled win32/64 externals and the modified karma~.c file.
      @Rodrigo thanks for the suggestions. I thought already about those strategies. The fact is that i'm restructuring an old patch/M4Live device of mine that use to have groove~ at its core, with karma~ (far more featured as a live looper engine). My device records realtime loops and save it in a folder. Every time a file is saved is added to a umenu that contains all the folder wave files. Then my device can scan the folder based on random process or via an user controlled parameter. For the [set] karma method i should dynamically create a new buffer everytime a new file is recorded. Quite a mess. But probably more reliable and time precise that [replace] on the same buffer. I should think about that and dive in Max patcher scripting to create new buffers. Have a temp buffer to record and then as many buffers as the files present in the folder. My device 2.0 version seems a little bit more far in the future :-) but i love challenges. a.
      ps...how do you tag people like raja here? with the @user_name formula? :-D
    • Aug 18 2016 | 10:44 am
      @Alfonso Ah yes, do please upload them, I can upload the github repo with them. Thanks!
      And yeah I figured you might have thought about some workarounds, but thought it was worth mentioning anyways.
    • Aug 18 2016 | 11:18 am
      here it is!
    • Aug 18 2016 | 12:04 pm
      hi guys, i wonder if you can take a look at this wich i believe is a karma/M4Live strange issue.
      The new karma~ version works kinda flawlessy in Max. But in Max4Live i have several issues.
      1. When i hit the [replace] message for the first time karma~ does correctly references the buffer. With previous version of karma~ gave me the buffer~ can’t read file now So far so good.
      2. When i hit the [replace] message a second time to load another .wav in the buffer i do have the buffer~ can’t read file now error as with the old karma~. In Max i don't have this error. I have it in M4Live only.
      3. In M4Live, when i try to start karma~ with my custom button i kinda hear a little click as if karma~ read a few samples than stops. This happens always. When i try to start karma~ with the plain [play] message the first time i hit it i have the same behaviour as before. The second time i hit it karma~ finally starts correctly and from this moment i can use both the [play]/[stop] messages and my custom button regularly. Some kind of init issues related to M4Live/karma~ combination? In Max everything works good with my custom button.
      I'm uploading my initial device for testing. Obviously for OSX a new compilation is needed on Mac with the additions suggested by Raja. Sadly i can't cross-compile.
    • Aug 20 2016 | 4:16 pm
      It must be something that M4L is doing different. Will keep it in the github issues to try to troubleshoot but neither raja or myself do much M4Ling, so it will be harder to track down.
      With regards to problem 3, it may have something to do with messages arriving within the same vector, which can sometimes 'break' the state machine. This bit of code will make sure consecutive messages (e.g. "play, stop, jump 0.5") are all delayed by the vector size. The problem might be something else actually, but this is an easy thing to test.
    • Aug 20 2016 | 6:13 pm
      thanks Rodrigo, i'll do some tests tomorrow. Regarding problems 1 and 2 for now i've switched to polybuffer~ using the [set] message for karma~. Problems 3 appears in some different occasions. I have to do more investigations. best
    • Sep 29 2016 | 1:25 pm
      Awesome job!
      The helpfile won't open in Max 5?
    • Sep 29 2016 | 2:31 pm
      Thanks!
      Hmm, I never tested the help file in Max5. Maybe it has to due with the 'tabs' interface? It's pretty self explanatory if you look at the video (or even screen shot of the help file).
    • Nov 22 2016 | 10:20 pm
      Hi Everyone and @Rodrigo
      I'm using karma as a sampler for a music instrument/sampler that collects sounds from records and trigger them with an interface that i m building.
      It may look like a stupid question, but I would like to know if Is it possible to avoid the looping of the recorded sound. I just want a play/stop function but i don't know how to do it.
      By the way thank you very much for your awesome job, it 's really f*&%in$ useful
      Nico
    • Nov 22 2016 | 11:57 pm
      Hi!
      Yeah it's not built to do that, but it is possible to do. If you look in the "misc" tab in the helpfile, at the "basic_looper" example, there is a subpatch called [edgeDetection] which does this. Basically if there is a jump in position if you are near the start/end of the loop it presumes you are 'wrapping around' and sends a stop message.
      This was done to emulate the "one shot" playback mode from the Line 6 DL-4.
      Hope that helps!
    • Nov 25 2016 | 4:05 am
      Yeah is exactly what I was looking for. Thanks a lot again
    • Dec 02 2016 | 5:58 pm
      Hey @rodrigo
      I am planning to use karma as an audio looper for live beatbox performances and I would like to know if there's a way to save wav files of the performance.
      Instrument is an accessible mic looper designed for people with visual disabilities and works with one button for record and play and another button for stop and reset.
      Do you think it will be possible to save a wav file of the performance when user will press reset button? I tried to use recorder and buffers but it doesn't work.
      Any help would be appreciated
      thank you again
    • Dec 02 2016 | 6:08 pm
      you can save the content of a buffer~ by sending a "write" message or have a sfplay~ before you dac to record the output
    • Dec 02 2016 | 6:18 pm
      The easiest way would be to use sfrecord~ to record the complete 'performance', but if you specifically meant to save the recorded "loop", then you can send the [write] message to the buffer, but that will write the complete buffer. Which, in most cases, *won't* be what you you record.
      For example, if you have a 10second buffer, and you record a 1second loop, sending a [write] message will save a 10second audio file, with 1second of audio and 9seconds of silence at the end.
      The solution to this would be to [crop] the buffer right before saving, but as I just discovered, karma~ leaves the buffer as 'dirty' meaning, it doesn't let you [crop] the buffer.
      But this would have been the solution to that, if that's what you wanted.
      If that is what you want, you can probably get around it by using mxj stuff to copy the karma~ buffer into a new buffer, crop that different buffer, and [write] it from there.
      If, however, you just wanted to record the performance, just sticking an sfrecord~ at the end of the signal chain is what you want.
    • Dec 02 2016 | 7:24 pm
      I have added a buffer copy and crop to Rodrigos Patch, using only max objects. One would prefer some kind of automated write messages in live situation, rather than sending write message and naming the files . That can be added if buffer storage is what You want.
    • Dec 03 2016 | 12:53 am
      Yeah that's a better way. And using only one variable for [crop] will work fine as long as you don't do any 'reverse recording' (start recording a loop while in reverse), otherwise you'll need both the start and ending values of the loop.