Magus patch projects log

Thanks, that’s helpful!

I get it with every patch I have created as well as the YM2413 Synth patch. So that could mean that it is something to do with Magus or it could be that the patches I wrote are failing to opt out of the “builtin amplifier”.

I tried testing this patch:

because it was the one patch I could find in the library that generated CVs. But whenever I boot it on Magus+732ceac17cb+a447765258d9 it crashes.

Here is the patch code for my patch where I am trying to output CV control but it’s being scaled by the volume. It is like an improved Midi Note Interface plugin. My processAudio is very simple.

Oh I see. You’re still using audio, not just CV as in parameter outputs like I thought initially. So yeah, this goes through codec and its programmable amplifier. I think that you should keep volume on maximum setting if you want to generate V/Oct CV. Also, if you change volume, you’ll have to recalibrate it (or return previous settings).

Also, we’ll probably allow setting volume from user patches eventually. So you could set it to max for V/Oct output or lower it for normal audio patches. I think it’s already possible by MIDI from external controller.

Yeah, I haven’t figured out how to use the parameter inouts for rapidly changing values. Earlier in this thread @mars said about parameters:

[quote]
The default buffer size is 256 samples, which at 48kHz sample rate means that block rate is 187.5Hz.
With the older codebase, on the OWL Pedal and OWL Modular, you can easily change the block size up to 1024, or down to 2 samples, which gives you a lot of range and makes audio rate parameters possible (up to 24kHz).
In the new OpenWare firmware we have not yet implemented a dynamically configurable block size[/quote]

If there’s a way in current OpenWare to dynamically configure block size I don’t know what it is.

If I’m outputting CV/gate I don’t necessarily need audio rate, but I might need better than 188hz to outrun MIDI?. (And I may start implementing things like an arpeggiator or sequencer soon, in which case 24kHz would be adequate but I would probably need things to change more often than every 256 samples…)

Also, we’ll probably allow setting volume from user patches eventually

When you reach this point I’d recommend some way to set volume temporarily/“locally”, IE, to say “set volume to 100% for me, but when you switch back to the other patch return to the previous global volume”.

Buffer size still can’t be changed. And with USB audio things are even more complicated now, so not sure when will this be working. I used to change it sometimes in old OWL FW.

BTW, that info is not quite correct. Audio block size is 64 samples, which is what is used for calculating latency. The number 256 is for the whole DMA buffer and it’s not particularly relevant as it’s 64 samples x 2 channels x 2 halves of buffer used for DMA. So we should be updating CV every 1.33 ms (or at 750 Hz rate if you like that better).

But I’m not sure how usable would be CV output in parameters - besides this low SR issue, it won’t have calibration applied. And it would have much lower precision (12 bits vs 24 bits). Though this would be still good enough for non-microtonal music.

BTW, that info is not quite correct. Audio block size is 64 samples, which is what is used for calculating latency. The number 256 is for the whole DMA buffer and it’s not particularly relevant as it’s 64 samples x 2 channels x 2 halves of buffer used for DMA. So we should be updating CV every 1.33 ms (or at 750 Hz rate if you like that better).

OK,this is all good to know. To be clear, though-- so that’s 64 stereo samples per audioProcess call, correct?. So that’s the fastest I can react to a MIDI change via “audio” (I don’t know how often processMidi can get called-- could it get called between every single audioProcess)?

Is it correct setParameter gets updated at the end of every audioProcess? So I guess I can react to MIDI on the audio channel exactly as quickly as I can react to it with a parameter…

I think the important question to me (for purposes of whether I can safely use setParameter) is whether this block size is predictable. That is, is it known at the time I compile with OwlProgram? Can I get it at runtime? (I can get the size from AudioBuffer when processAudio is called, but can I assume processAudio always uses the same buffer size?) If the block size (and therefore the parameter refresh rate) can vary between devices or between OpenWare versions then that makes it a little awkward for, say, gates-- if I code my patch to send a pulse on a parameter plug I can’t predict exactly how long that pulse will be held…

Yes, that’s how it works

It’s the same on all current devices and probably won’t be changed until it can be overridden at runtime. If that happens, we’ll likely be restarting current patch to change buffer size.

Even though we currently use the same settings, such things should be calculated at runtime based on AudioBuffer size and sampling rate. You’re looking at it from the opposite direction - if you need to send a pulse that is held for certain number of milliseconds, you should count how many calls to processAudio its bound parameter must be set to high.

This is all very helpful, thank you.

So I’ve got a few patches added to my patch repo now:

  • ScreenSaver: This is deeply useless, it plays no sound and draws random numbers to the screen
  • Silence: This does nothing at all, which is actually useful— I now have this set as my patch 1 so that when I first turn on the Magus it makes no noise and draws little power
  • Midi2CV: As described above this plays. It is an improvement on the “Midi Note Interface” on rebeltech/patches in that it has correct monophonic behavior (if you hold down two notes it will play the more recent one, and retrigger if the second note is then released) and it displays which notes are being held down (I am still struggling with whether to display right-to-left or left-to-right).

I uploaded Silence and Midi2CV to rebeltech/patches (although since USE_SCREEN is off on rebeltech.org, it does not have the screen display in this version). I think next I will try to add RPEG to Midi2CV and maybe make a simple sequencer.

With Midi2CV I can now use the Magus to play my eurorack from a MIDI keyboard! Before I could only do that by getting a laptop in the loop. (My eurorack doesn’t have an oscillator so if you look carefully at this patch you might notice I’m actually using an oscilloscope as my oscillator…)

Super excited to have the Magus fully working now!

1 Like

Nice!

I’ve got a PR in the works that will finally allow us to compile screen patches with the online compiler.
Note though that the API is changing. Instead of specifying PLATFORM=xyz, all the screen-specific code has been moved to a new base class. So in the future you will need to use this:

class KickBoxPatch : public MonochromeScreenPatch {
public:
  void processScreen(MonochromeScreenBuffer& screen){
  }
};

The ScreenBuffer i/f statys the same, bar a couple of new drawCircle/fillCircle methods courtesy of @antisvin.

I wonder if SevenSegmentLEDScreenPatch will be a thing eventually :wink:

Okay, cool. One thing that I’d ask though is you make sure it remains easy to switch between building with-screen and no-screen patches by #if-ing on USE_SCREEN. (This is probably possible even with a subclass because the developer could #define the parent class name.)

By the way, could I drop a few feature requests on you? These are just suggestions but…

  • Would it be hard to add support for directories to the https://www.rebeltech.org/patch-library/patches upload interface? My patch repo now has a subdirectory of shared support headers, but I have to garble the file names when I upload to the patches website because the patches website puts all uploaded files in one dir.

  • Is there any way that I could draw input from the headphone jack input and the modular input at the same time? Or mix it so that the LEFT_CHANNEL samples come from the headphone jack and the RIGHT_CHANNEL samples come from the modular input? I’m asking this because it would be nice to be able to take input from my eurorack and my non-eurorack drum machine at the same time.

  • Let’s say I want to make a parameter that takes a limited number of discrete values— like, “Drone mode: On / Off” or “Mode: Drone / Midi / Random”. How would you recommend doing this? getIntParameter()? Does getIntParameter just map the -1 … 1 input range to an integer range? Is there a way to set up getIntParameter so that one tick of the knob corresponds to a single change in integer values?

    • Alternately: AudioUnits have a feature where “names” can be assigned to the values of integer parameters; when the interface is drawn, the patch object gets called with the value it wishes to display and is given a chance to return a custom string instead of the value. Would you consider a “parameter to string” feature like this? You could for example implement this as an overloadable method on Patch that returns a char *, when you are going to draw the “PARAMETER D [bar here]” at the bottom when the knob is being turned, if the returned string is non-NULL you could display that strihg in place of the bar. For some things this would be easier than custom screen drawing code.

I imagine you’d need to use a stereo to mono splitter for that (and leave one of inputs unconnected). This is dealt with in analog part of Magus, audio codec just processes whatever it gets as inputs in its 2 channels.

That’s how getParameterValue() works (except that it uses 0.0 …1.0 range). You can get parameter values scaled to any range with getIntParameter()

Encoder sensitivity can be changed and parameters don’t know if they’re controlled by encoders or pots or MIDI or from patched directly. But you can always track this with a separate value that counts increments/decrements:

if (prev_param > param)
    value++;
else if (prev_param < param)
    value--;
prev_param = param;

That would require making 20 function calls on every screen update even if this feature is unused. I think you should just draw a custom UI.

Oh, cool. To be clear, there’s nothing like a mixer here, right? But if I plug in a splitter it’s safe to use either one of [left audio channel 3.3V range] or [left modular channel 5V range]?

I’ll try this, I think I might need to add some debouncing but it should be enough for now. But, it seems like it would be better if the OpenWare layer handled this, because if I did it this way wouldn’t the parameter get “stuck” if you turned it all the way to the 0 or 1 limits? OpenWare “knows” that the rotary encoders are rotary encoders but my patch does not, my patch only knows it’s looking at a value between 0 and 1.

Well, I wasn’t thinking of the little “all inputs” thing at the bottom, I was mostly thinking of the separate “big” bar right above it. There’s the grid of bars at the bottom, but above that there’s a label for the last parameter turned and a bar for just that last parameter. OpenWare knows which parameter is being displayed there at any one time, but I don’t. If I knew what parameter it was displaying I could erase the bar and draw in text of my own.

(I find an onEncoderChanged in patch.h, which could potentially solve two of my problems above because I could (1) get a raw encoder delta out of it and (2) use it to track which knob was last turned, but in both cases I don’t know how to find out which parameter the menu interface has currently mapped to which knob.

By the way, what does the “samples” parameter on encoderChanged and buttonChanged mean?)

You shouldn’t need debouncing in this case as you won’t be getting raw encoder values.

I see - well that’s less problematic. I think that if you care about such feature and can provide an update and sample patch to test this, Martin likely wouldn’t mind adding this to OWL.

This is code that renders active parameter. So I think you’d need an extra callback function which would be registered by the patch, if it’s present than it should be called before last line that renders rectangle. And if that function returns non-empty result, it would be printing text instead of drawing rectangle.

I think that would number of samples since last click.

1 Like