ofxStk, Synthesis ToolKit addon

I made an addon, for Stk. I chose not to wrap into another api because stk already works well with openframeworks. You can find it here https://github.com/Ahbee/ofxStk.

4 Likes

I added more examples. I added ‘Drawsynth’ which shows how to build a synth with adsr. I also updated the file loop example to involve basic chorus and reverb effects.

Fixed a bug in the ADSR envelope of drawsynth. I was updating the adsr each frame, which can cause problems. You should not update the adsr while the synth is playing.

Will you be adding a effects example any time soon? I’m still having a bit of trouble understanding how to link the classes easily together. Thanks much.

@michaelpromeo, I updated the FileLoop example to include some of the built in Effects. However it does not demonstrate how to do custom effects. But custom effects are pretty easy to do(subclass Stk::Effect and create a tick function). If you have a custom dsp algorithm I can post the STK code for you.

I’m trying to use ofxStk in an iOS application. I’m having two issues which I don’t think are related to iOS but I can’t be sure,

  1. When I try to build by just including the ofxStk addon it can’t find ‘SKINI.msg’
  2. Because PI is defined in STK it is conflicting with oF when trying to run in iOS

you can definitely get it to work on ios. I’ll give it a go tomorrow.

Ok answered my own issue. I got ‘STK’ working on my iPad by doing the following:

  • Removing references to the ‘SKINI.msg’ and ‘SKINI.tbl’ files in the xcode project navigator.

  • Adding the correct header search paths.

  • In the case of conflicting ‘const PI.’ I simply created my own ‘const float myPI’ and set it equal to PI.
    There is probably a cleaner way to do this part, but it worked in my case.

@michaelpromeo, Can you you use project generator to install the addon. I did that and it complied withput any problems.The two problems you mentioned never occurred with me. The Skini files are necessary for stk to compile. And the PI def should not be a problem because I undefined it, then redefined it.

There is one more thing you need to do. At the start of your app before anything you need to put the line

 stk::Stk::setRawwavePath(ofToDataPath("rawwaves"))

this also means you have to allocate all instruments on the heap,after the line stk::Stk::setRawwavePath(ofToDataPath("rawwaves"))

Here are the three steps you need to follow to use ofxStk for ios

  1. Use project generator to install addon
  2. Copy the rawwaves folder from the example, to your bin/data folder
  3. call stk::Stk::setRawwavePath(ofToDataPath("rawwaves")) before you make any calls to stk;

I understand what you’re saying and the Project Generator worked for me as well. However, I wanted to insert the addon after the fact with the OF addon Plugin. In my case, the above steps had worked. When I say ‘removed’ the ‘Skini’ files I just meant I couldn’t build with them in my xcode navigator area. As far as the PI issue, it was conflicting with my usage of ‘PI’ in openFrameworks. In the stk.h library ‘PI’ is defined as a constant there as well.

I’m not sure whether this is a ofxStk question or general audioOut() question but I’ll give it a shot. I want to make multiple objects of a class that includes stk::fileLoop. Once I make more than one object I don’t get any sound playback.
Any idea how to do this?

Are you sure you are not closing the FileLoop? Opening and playing multiple fileLoops does not cause any problems for me. I would have to see more code.

Hey Ahbee
i am using this great addon in an iOS app. i want to be able to pitch-control several samples.
I studied therefore your pitchShift example.
I guess, i have to add each sample as an instrument to the voicer?
but how to choose wich sample (-> instrument) i start on noteOn?
Thanks

I need you to be more clear.
1.Do you want to create several instruments ,each based of a single sample(a different sample for each instrument)
2.Do you want to create a single instrument, that triggers multiple samples simultaneously.
3. Do you have a single instrument with multiple samples mapped to different regions of the keyboard,but each region only works with a single sample.
4. No instruments You just want to playback samples with different pitches?

Or are you trying something else?

@michif, I added instuctions to the github readme for ‘creating custom instruments’

thanks!
basically, I want to playback diffrent samples with different pitches. I think, I want to do it like 1) or 4).
But I guess, I don’t fully understand the voicer/instrument concept yet. maybe I should use fileLoop for that?

I want to have it like pressing button A will play sample 1 at pitch X, button B will play sample 1 at pitch Y, button C will play sample 2 at pitch Z.

Edit:
I now add the diffrent samples as diffrent instruments with specific group numbers to the voicer. seems to work like that for now…

Hello,

great Toolkit! I’m using STK in a custom class to provide buffered audio/videoframe playback. So far it works like a charm!

I’m trying to implement a multi-channel bus functionality now, but I’m a bit lost how to achieve this. I guess in pseudo-code form what I want to achieve is this:

if (bAudio) {
        // create a frame to hold n samples (~bufferSize) for m channels (here: 4)
        stk::StkFrames frames(bufferSize,4);

        // all mono samples, but audio should go to different channel in multichannel frame
        // error: only tick(frame) is a possible method, but where to provide channel?
        sampForCh1->tick(frames,0);
        sampForCh2->tick(frames,1);
        sampForCh3->tick(frames,2);
        sampForCh4->tick(frames,3);
 
        // update arrays for audio card
        for (int i = 0; i < bufferSize ; i++) {
            output[2*i]   = frames(i,0);
            output[2*i+1] = frames(i,1);
            output[2*i+2] = frames(i,2);
            output[2*i+3] = frames(i,3);
        }
    }

I seems best to me to keep having one StkFrames with all the audio values in it, no? Or am I misunderstanding something?

Best,
Vincent

Yeah you are right, the effects and instruments do have a function that looks like StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ) but for some reason the fileplayback class does not have it.

I guess your only options is to do something like this.

for (int i = 0; i < bufferSize; i++) {
        frames(i,0) =  sampForCh1->tick();
        frames(i,1) =  sampForCh2->tick();
        frames(i,2) =  sampForCh3->tick();
        frames(i,3) =  sampForCh4->tick()
    }

I can add a function to the fileplayback class that looks like this. which will do what you want

stk::StkFrames& tick(stk::StkFrames &frames,unsigned int channel = 0){
        stk::StkFloat *samples = &frames[channel];
        unsigned int hop = frames.channels();
        for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
            *samples = tick();
        return frames;
    }
}

but the problem is I cant seem to get in touch with stk authors.I dont want to modify stk source without knowing the consequences. I’ll try emailing the authors directly and ask them. sorry I coudn’t be more help.

Hello Ahbee,

thanks for your comment. It’s actually very helpful!

I completely understand that you don’t want to modify stk without consulting the authors. I’m curious for their response.

I’m gonna go ahead with your examples.
Best,
V

@Vjacobs Turns out there is an official stk repo (never knew!) . I submitted 2 pull requests, one for your request and another for the bug in PitShift . These changes are already committed inside ofxStk

update: The changes are now in the official repo.

Hello Ahbee, thanks for the follow-up!

When using the function you provided, I had to make the following change to be able to route more than one sample to the same channel (for instance samples 1 - 3 - 5 go left, 2 - 4 - 6 right).

*samples = tick();

becomes

*samples += tick();

I then use it like this

    // create a frame to hold n samples (~bufferSize) for m channels (here: 4)
    stk::StkFrames frames(bufferSize,AUDIO_CHANNELS);
    // put sample data in frame. The buffer takes care of putting it at the right channel in the frame
    for (const videoPanelRef panel : panels) {
         panel->getBufferRef()->tick(&frames); // goes to audioRef->tick(frames, mChannel);
    }
            
    // update audio card with multi-channel frame
   for (int i = 0; i < bufferSize ; i++) {
        for (int j=0; j<AUDIO_CHANNELS; ++j) {
             output[AUDIO_CHANNELS*i+j] = frames(i,j);
         }
    }