Magus patch projects log

Hi my name’s Andi, I make video games and confusing generative art but I used to make glitch music and I would like to get back into making music! I have been playing around with Eurorack stuff but not making much progress, but I got a Magus and I hope it will be my leg up into my dream of making sounds that give people nightmares.

I am going to post my progress with writing Magus patches (and maybe eventually firmware mods?) in this thread. If that is not an okay use of the forum let me know.

So! I sat down today with my new Magus and tried to make a C++ patch. I didn’t quite succeed. Here is the patch I made:

But, it does not work. I wanted it to be a mix of four sawtooth oscs with independent detune controls. I was able to put out audio but not the audio I wanted, meanwhile the CV out is definitely wrong and the params are not laid out on the Magus patch board how I expect.

Any help much appreciated! :slight_smile:

GENERAL QUESTIONS I HAVE:

  • I find that when the Magus is being powered by USB from my Macbook, there is a quite prominent buzzy hum on the Output line when nothing is playing or when quiet sounds are playing. I do not hear this hum when I am powered from the 9Volt wall adapter. The hum does not seem to impact the voltage out on the CV patch points, I only hear it on the “out” plug on the back. The hum is audible both with headphones and with a 1/8-inch cable running to a small bluetooth speaker I own. The hum sounds a lot like the classic “60 cycle hum”. Has anyone else encountered this, is there any way to mitigate this?

  • Is there any way to delete, or reorder, patches installed on the Magus? (I would like to have it default to a “silent” patch).

C++ QUESTIONS I HAVE:

  • How do the parameters get laid out with regard to the knobs and the patch points? The sheet that came with the Magus says each knob corresponds to 4 parameters with 4 patch points each. I assumed that means the IDs for each group of 4 would bunch together, but the definition of PatchParameterId in openware OpenWareMidiControl.h is just… confusing, it has 5 bunches of 8 letters. I tried listing my 16 parameters as A through AH, and I tried listing them as AA AB AC AD BA BB BC BD… but neither way did what I wanted.

  • What is the sample rate, or can I query it at runtime?

  • What is the floating-point range of parameters (-1…1?)? What voltage range does this correspond to in the CV patch points (-5…5?), or can I query that at runtime?

  • KickBoxPatch.hpp in the marsus MyPatches repo, which I used as the basis for my patch, includes a VoltsPerOctave.h. Several of the other files in that repo include an Oscillator.h that seems to be ultimately generating their waveforms. But I don’t find VoltsPerOctave.h or Oscillator.h in either the marsus or OpenWare repos. Where are these files? I think it would be easier for me to write an oscillator-like patch if I had some PCM-level sample code to inspect.

  • When I tried adding exp2f() to my patch, the Magus locked up hard. When a version of my patch that calls exp2f() is executed, the knobs stop responding, audio stops playing and I cannot select another patch. What could be happening here? (The function is used in KickBoxPatch).

  • When are the appropriate times to call getParameterValue/setParameterValue? When I wrote my patch, I wanted to have the current waveform value of each of my 4 sawtooths output to the patch points. And it occurred to me that I might want to plug one of the output patch points back into an input patch point and have the parameters modulate each other in real time. So in the code linked above, I call getParameterValue every time I iterate a sample, and setParameter every time I write one. But I found that first off, my patch was very inefficient (it takes up 92% CPU even though as you can see it does very little-- I worry this is because I am calling getParameterValue in a tight loop) and second off the output does not seem to be updating on every sample (it sounds like crackly noise and when I looked at it on my scope it looked like chunky runs of single values). Intuitively it seems like if you are sending or reading a waveform on the patch points then the i/o should look something more like an AudioBuffer than calls to get/set parameter values…?

  • Something @Mars said in another thread made it sound like there is smoothing on the encoders-- is there any way to have the smoothing work “during” the span of a single processAudio(AudioBuffer) call? For example, I have used another audio API where if the audio system knows that one of the parameters to a sound module is currently being smoothly interpolated from one value to another, when it asks that module to generate a block of audio, it tells it the beginning and end values for the time slice it is requesting values for, so that the module can internally interpolate the parameter values during its pcm generation. (I am not sure I have asked this question clearly, sorry.)

  • I notice there are a lot of tutorials on rebeltech.org. Do any of these discuss how to make a C++ or FAUST patch for OWL/Magus? Most seem to be MAX.

NOT A QUESTION, BUT THIS SEEMS LIKE A BUG

In the first version of my patch, I tried calling snprintf() to create the name strings for the parameters. I found that if I call snprintf() the whole program fails to compile with a link error:

/opt/OwlProgram.online/Tools/gcc-arm-none-eabi-7-2018-q2-update/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard/libc.a(lib_a-sbrkr.o): In function `_sbrk_r': sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk' collect2: error: ld returned 1 exit status make[1]: *** [/tmp/owl/owl-build-aCJIVa/patch.elf] Error 1 make: *** [patch] Error 2 ERROR: Patch build failed.

I was able to work around this bug by using strncat instead. But, is there a way to get this filed as a bug? snprintf is a pretty normal function to call. I think the error means snprintf() contains code to allocate memory in a way that is not supported on the Magus platform.

Hi Andi,
My Magus hasn’t arrived yet and I’ve just used Owl Modular before, but I think there are a few question that I can answer before Martin joins in.

  1. It’s very common to get noise whenever you power your audio devices from USB. Usually it means you have a ground loop. I use an adaptor from Arturia Beatstep that lets you take power from one source and USB data from another, this solves the issue every time.
  2. I suppose this the V/O header file you were looking for is OwlProgram/VoltsPerOctave.h at master · pingdynasty/OwlProgram · GitHub
  3. For sample rate you should use .getSampleRate method from your Patch subclass - OwlProgram/Patch.h at master · pingdynasty/OwlProgram · GitHub . I think it’s 48000, but the actual value should matter only if you’re resampling audio.
  4. Besides tutorials here, they had some info API docs for C++ on the old OWL site - https://hoxtonowl.com/mediawiki/index.php/Main_Page . Right now that site is timing out when I try to access it. You can check copy in archive.org, but I think it had some general guidelines and autogenerated API docs for C++ classes from the repo mentioned above.
  5. I think that tutorials were mostly made for PD&MAX because they are the most newbie-friendly environments for DSP development that OWL supports. If you want to understand what could be done in C++/Faust, your best bet is to have a look at GitHub - pingdynasty/OwlPatches: Audio Patches for the OpenWareLaboratory: http://hoxtonowl.com</t . There’s no API or extra libraries for Faust, just some conventions for specifying how values (CV or MIDI) are bound in labels for “slider” inputs, so very little OWL specific info to be told in tutorial.

@antisvin, thank you!

That is good news that the noise can be fixed, I will try with a powered usb hub and see if that helps.

Your other advice helped. I rearranged the code some and I am now able to call exp2f() and it works. I’m not sure why it was locking up before. Maybe I was calling exp2f() too often and it could not handle it because that function is slow somehow…?

In the version of the patch currently uploaded I’ve figured out:

  • What is the sample rate
  • I have the parameters laid out right (I still don’t know why exactly, but I just experimented until I found an ordering)
  • A way to remove the hum according to antisvin

I am still confused about the other things I asked about though. (Also it doesn’t make sound yet, but I think I just calculated frequency wrong… I’ll fix that on my own tomorrow)

The device I’ve mentioned is not a USB hub and I wouldn’t expect a HUB to help here. It’s merging power supply and USB data from difference sources (with power coming from PSU connected to mains power). This device is on the left of the image - http://routenote.com/blog/wp-content/uploads/2017/03/pasted-image-0-5.png . There’s plenty of special ground loop isolators that may work as well.

Regarding DSP load from exp2f, it’s not a problem if you run once per audio block (i.e. for tuning calculation). If you want to run it at audio rate, you should consider using a LUT with precomputed values.

Thanks again.

I’m trying to bring in AudioDisplay.hpp from the Mars/MyPatches repo (this seems to be the best way to get a waveform visualization while the app is running?)— what headers do I need to include to be able to use AudioDisplay.hpp? It seems like something is being indirectly included in the KickBoxPatch example.

If I just include “AudioDisplay” I get various errors like “Invalid Configuration” and “Colour does not define a type”. Combinations such as #include "StompBox.h" #include "VoltsPerOctave.h #include "AudioDisplay.hpp"" or #include "device.h" #include "ScreenBuffer.h" #include "AudioDisplay.hpp" did not do it.

@mcc are you compiling offline using OwlProgram, or online by uploading your patches?

Compiling with support for patch screen control is not activated by default, but you could try compiling with make PLATFORM=Magus ...

exp2f is implemented internally with a fast LUT so it should perform well - unless you compile without --fast-math which should be set by default. If not, try using fast_exp2f instead.

I’m compiling with the rebeltech.org “My Patches” website upload.

Okay so we’ve not yet enabled compiling platform-specific patches with the online compiler, which is what is required for screen support.

Ahhh, good to know. I’ll just not bother with the screen until I can get a compiler set up locally…

Progress today:

  • My sawtooth oscillator works! https://www.rebeltech.org/patch-library/patch/AndiSaw4
  • While I was trying to fix the sawtooth oscillator, I accidentally made something way better https://www.rebeltech.org/patch-library/patch/AndiSewage
  • As part of debugging this, I wrote a lil Python script that converts the .hpp files the RebelTech “patches” website ingests into standalone executables that run the patch for a second and emit the output sound as printed values or as floats Audacity/Amadeus can import. I suspect the OpenWare repo has something like this already but I haven’t figured out how to use that stuff yet. I find this a little more useful than the WebAudio embed on the web page because I can look at the waveform values instead of trying to debug by listening. I uploaded this to GitHub - mcclure/MagusPatches: Patches for the rebeltech.org magus (to test it, try: ./MagusSim/MakeMagusSim.py Saw4Patch.hpp && ./Saw4Patch --human -s 50 )

I haven’t recorded anything yet.

Saw4 todo: - Overdrive should probably be a log scale - Wave output updates only every processAudio() call, not every sample - Need to learn to compile locally and add screen support

Things I am still trying to figure out about Openware:

  • When computing a block of samples in processAudio, how do I send samples to an output parameter on a per-sample basis (instead of calling setParameterValue once a processAudio call)?
  • Can a Patch tell whether a particular patch point has a cable plugged into it?
  • Once I learn to build locally, what type of file do I upload to rebeltech.org if I want to share in the “patches” section?

What exactly are the voltage ranges of the Magus patch points?
In my testing it seems? like the bottom 16 patch points are limited to the 0-5 range but the top two right outputs that correspond to “audio out” are in the -5-5 range. But I am not quite sure.

When computing a block of samples in processAudio, how do I send samples to an output parameter on a per-sample basis (instead of calling setParameterValue once a processAudio call)?

You don’t. Your code receives a buffer of incoming audio samples and a set parameters, then you can output outgoing buffer of audio and change paramers. You can’t work on per-sample basis with parameters as they are neither bufferized nor can be read/written at audio rate.

Can a Patch tell whether a particular patch point has a cable plugged into it?

Nope, pretty sure it’s impossible.

Once I learn to build locally, what type of file do I upload to rebeltech.org if I want to share in the “patches” section?

Whatever sources you’ve used for building them

Hm, ok thanks. That sounds unfortunate and much limits the utility of the device, since it means the patch points would need to be limited to values that update slowly or infrequently… like it seems like you couldn’t implement things like FM operators and self-patch with a limitation like this. (I haven’t yet figured out exactly what the typical callback buffer size is, since I don’t have the screen working yet, but it seems like a human-noticeable amount of time…)

OK. Cuz it seems like the magus can tell if things are plugged in or not (it seems like if i plug in and then pull back out it snaps back to the last value i set by knob)

OK. So I take this to mean that right now you can’t currently upload patches that draw to the screen (because device-specific builds are not implemented)?

You can’t work on per-sample basis with parameters

That is correct, but you can work with small buffer sizes to get audio rate parameters. 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. It’s not been a priority, since we’ve not so far seen a lot of demand for this feature. But it will still get done, eventually :slight_smile:

What exactly are the voltage ranges of the Magus patch points?

The audio ins/outs (top two jacks left and right) are +/-5V, while the bidirectional CV patch points (all the other jacks) are defaulting to 0-10V ie unipolar. The hardware supports different configurations, they can also be +/-5V or -10V to 0V, input or output.

Can a Patch tell whether a particular patch point has a cable plugged into it?

The patch only deals with the abstraction of a pararmeter, and doesn’t know if the value has been set by CV, MIDI or your hand. Or if a cable has been plugged in.

right now you can’t currently upload patches that draw to the screen (because device-specific builds are not implemented)?

You can’t compile them online yet, so we won’t be able to load a sysex directly from the patch page. But you can still share the source.

A (low priority) web feature that’s been on my todo list for a long time now is the ability to upload a pre-compiled binary, which would be useful in situations like this.

Also a quick note about drawing to the Magus screen. You can actually print a message, and up to three numbers, without using a special compiler flags or anything. In C++ simply use debugMessage(), ie one of:

void debugMessage(const char* msg, int);
void debugMessage(const char* msg, int, int);
void debugMessage(const char* msg, int, int, int);
void debugMessage(const char* msg, float);
void debugMessage(const char* msg, float, float);
void debugMessage(const char* msg, float, float, float);

In Pure data you can send to a print object and it will show on the screen.
Only the most recent message will be visible, so you can use it to display variable values in realtime, but you won’t get several messages showing one after another because they’ll be overwritten too quickly.

That sounds unfortunate and much limits the utility of the device, since it means the patch points would need to be limited to values that update slowly or infrequently… like it seems like you couldn’t implement things like FM operators and self-patch with a limitation like this.

And that’s why they’re called CV patch points, not audio patch points. Also, if you would try to pass audio for FM like you describe, it would be making a roundtrip through output and input buffers. This would increase latency and I think it would also be giving you jitter in your modulator’s phase that would make your waveshapes inconsistent.

it seems like if i plug in and then pull back out it snaps back to the last value i set by knob

I’ve just received mine yesterday, didn’t get to play with it a lot. But I suppose encoder is setting an offset for incoming CV that doesn’t change, so you would get the same value by pulling the plug out as sending 0V.

@mars, @antisvin, thank you, this is all very useful!

It makes sense the Patch API would be more limited than the Magus itself since Patches are meant to work on multiple devices… I can work within those limitations for now until the firmware gets upgrades or I figure out how to build firmware myself :slight_smile:

1 Like

Tested more with my saw4 patch today. I realized my MIDI support was broken so I fixed it. https://www.rebeltech.org/patch-library/patch/AndiSaw4 sets its root note on MIDI input correctly now. I had some fun plugging the Magus directly into my Minibrute 2 finally— magus took MIDI in from the brute, put its output into the Minibrute 2 EXT, and I was able to detune my saws and hear my synth as a voice on the Minibrute with the brute’s cutoff ADSR and everything. Wheee!

I did discover something weird. While I was testing I downloaded https://www.rebeltech.org/patch-library/patch/YM2413_Synth and https://www.rebeltech.org/patch-library/patch/FmDronePoly to the magus and tried MIDI controlling them from the Minibrute keyboard (Magus as host brute as device). What I found on both patches is if I played lots of notes, occasionally (pretty frequently actually) there would be “note off” messages that got dropped. So single notes would just sustain forever. It seems unlikely that both of these patches just happened to have the same bug, also when I tried running the Magus in device instead of host mode (IE connecting it to a computer and sending MIDI from there) I could not reproduce the issue even with 5 or 6 notes playing at once. It seems as if NOTE OFF messages are being dropped by the Magus itself when it is in Host mode. @mars is this surprising?

1 Like

So after finally getting a custom firmware built and solving my knob / MIDI drop issues, I’m back to trying some patch dev! :slight_smile:
I am encountering some new questions… My main one right now is—

I am a bit confused by the debugMessage function… I’m running this:

  void processScreen(ScreenBuffer& screen){
    static int q = 0;
    debugMessage("Frame count", q++);
  }

When I run this, I get a single number the first time I knob over to the “Status” screen. This number seems to never change. I can knob away from “Status” and back, it is still stuck on one number. If I press down on one of the bottom four knobs and then re-knob to the Status screen, the number changes. What is the correct way to use “debugMessage”?

Other, kinda specific questions:

  • Is there a way to not clear the screen between processScreen calls?
  • I notice that my patch outputs are scaled by the current “volume” number, not just on the headphone output but also on the top right (processAudio) CV outputs. This could cause problems for patches where the realtime CV outputs are used for triggers or CV note values. Is there a way to set separate “volume” for the headphones and the CV? Is there a way for a patch to opt out of the “volume” control for the CV outputs?

I am testing on git:732ceac17cb merged with a447765258d9.

Display is always drawn starting with an empty buffer in this callback function. That’s because Magus will update results that your buffer outputs before showing it and we don’t want to allocate a new buffer for that. But you can easily keep a copy of it between draw calls:

This should require copying a buffer of 8Kb for current display size. Btw, I think this class needs a method for calculating this like

void getBufferSize() const {
    return sizeof(Colour) * width * height;

Also, you should be using just object members to store data like frame counters, there’s no reason to use static variables here.

I don’t think that volume has anything to do with CV level, it just sends a specific command to audio codec’s builtin amplifier. Do you get this effect in every patch?