Resources usage

So I was reminded that we have an extra SPI NOR chip thanks to Magus kickstarter stretch goal. I’ve found driver for this chip in repo and its datasheet. STM also has a nice header for larger version of this chip.

I’m not sure how much we can achieve without memory mapped mode support. I think this would require a separate storage and different access from user patches. We would have to add a service call for copying data from resource header pointer (using it as address only).

Defrag would also be a bit harder - currently we copy data to memory, but 8Mb is too much. It’s possible to erase data in 4k or 64k chunks, so we’d have to use buffer to erase data gradually. Also, refactoring done in Daisy branch allows us to use arbitrary alignment (as class template parameter). So we could align by sectors or blocks to make defrag code simpler.

Initial support for access to resources has been merged to development branches of OwlProgram/OpenWare. This enables read access to any flash resource by name and converting resources to array data.

There’s also Magus-specific code for overriding RGB tables with custom color schemes and resource browser UI page.

The outline of the process, to add resources to C++ patches, is:

  1. Declare a Resource pointer in your Patch class:
class MyPatch : public Patch {
  Resource* myresource;
  1. In your constructor, call Patch::getResource() and get the data from it that you need
  MyPatch() {
    myresource = getResource("909kick");
    FloatArray samples = myresource->asFloatArray();
  1. In your destructor, call Resource::destroy() to clean up memory allocations
  ~MyPatch(){
    Resource::destroy(myresource);

Of course this needs the latest develop firmware and OwlProgram to actually work, and you need to first store the resource on the device as well (roughly same method as storing patches, but with slot numbers starting at 43). We’ll be publishing more info on all of this shortly as we catch up with docs and releases.

Great work on this @antisvin, thank you again for your amazing PRs!

It may be a little bit earlier to advertise this API, I expect that it would require a few more updates to get everything right in OwlWare repo.

Also, I wonder if anyone except @mcc would dare running code from development branch :wink:

Would a test be helpful? I have use for the resources API (I’m making a small sequencer) and also I was considering doing a firmware update for the reasons I describe here. The thing is tho it is very important to me to retain MIDI HOST functionality so I don’t want to upgrade master if MIDI HOST is going to break like it did in my test with d6c58cf8ec6126

Yeah, it should work for storing sequencer data. There are 2 gotchas that I can think of here:

  1. There’s currently only 12 slots allowed for resource data, one of them is occupied by firmware settings. So using it to store each track in a separate slot would be limiting.

  2. I’ve made a simple script to generate resources from binary files, tables in C headers or WAV file bodies - OwlProgram/makeresource.py at develop · pingdynasty/OwlProgram · GitHub . It’s intended to work with simple arrays, you may have to add zero padding to get correct alignment for storing datastructures.

I might be ok with a small limit of resources, especially if there is some way (in principle) to back them up to a computer. Can resources currently be loaded/stored on the computer side?

One thing that might help with the 11-slot limit is if it were possible to load or save just a part of a resource (memory mapped mode would effectively give this too). If there’s a limit of 12 resources, then my thought is I should just create one resource per patch, and have the resource contain an array of presets within it. However at that point I would be worried about running out of RAM from loading the entire combined-resource into memory, or crashing while writing a single sub-resource and corrupting the entire combined-resource. If I could load or save a range of the named resource I could avert both these problems. I haven’t checked out the header yet to see if there is anything like this.

Supporting resource downloading sounds like a good idea. I can’t find anything like that in current sources, but recently added background tasks support could be used to implement such feature. For now you should just store a copy of your resources before uploading, but it likely would be possible to download them from device later. There were other planned enhancements for this, i.e. web based tool for browsing/managing resources, resource upload in web UI, etc.

Btw, don’t worry too much about number of resource slots - it’s just the beginning. There’s an extra chip with 8MB storage that would be supported in the near future. It would further complicate some things, as we’ll have to deal with 2 separate storages. But at least it would solve the storage space issue. It does have one limitation - you’ll have to load resource from that storage to RAM, while with current flash storage you can read data directly without using an extra memory buffer.

Is there in principle a way of loading resources on/off of the device with FirmwareSender? Shouldn’t that be able to download and upload whatever flash it needs?

Yes, FirmwareSender works with them the same way as patches (there’s no difference at its level). But I’m pretty sure that it doesn’t read from device slots, there’s just no support in current MIDI protocol for that.

Btw, there’s also integration in OwlProgram for uploading resources now, you can use something like make RESOURCE=/path/to/resource SLOT=SLOT_NUMBER resource . Resource slots follow patch slots, so 42 would be used by settings and you can write your own data in remaining 11 slots.

If it works correctly, new firmware will show upload progress bar and you will see new resource in resource browser page. You can also delete from that menu after clicking on it to enter delete mode. And resources that start with double underscore would be write protected in that menu (but can still be overwritten).

The current state of play (ie develop branches):

  • firmware supports new SysEx functions for storing a resource by name, and for retrieving stored resource names
  • Patch class has a new Resource* Patch::getResource(const char* name) function
  • FirmwareSender has been updated to pack, send and store a binary resource by name
  • resources such as samples can thus be stored by the user and accessed by a patch

To test it I’ve been doing the following:

  1. convert wav file to 48k mono float32 raw file with sox:
    sox sample.wav -r 48k -c 1 -t f32 sample.raw
  • send raw file to device and store as sample.wav:
    FirmwareSender -in sample.raw -out "OWL*" -name "sample.wav"
  • load test patch, e.g. ResSampler

I’ll create a simple web utility to upload resources, and a method for deleting (uploading with the same name automatically replaces an existing resource).

Would be great to have the ability to upload a wav in the browser and convert it to the correct raw format with JS, but that’s way beyond my front end coding skillz.

I think that we’ll eventually start supporting storing WAV files in resources. Then we could have a few service calls for getting WAV data or individual cue points. In such case, only non-audio data would require storing raw data as resources.

I would like to follow up on this…
Based on the notes on the 22.4 release it sounds like resources are now a working/shipping feature!
I see resource is documented in the API now.
I am going to update to 22.4 and try to write a patch on my Magus that uses resources.
I was wondering, is there a specific patch where source code is available that provides an example of using/selecting resources? This would save me time.
This thread mentions a “quad sampler” patch, but I didn’t find that patch in either the OwlProgram repo or in rebeltech.org/patch-library. Does “quad sampler” use resources? Is source available?

Hey Andi, welcome back!

Resources were usable for a while now, aside from a few changes to its API while we were still deciding how to make them convenient enough.

Here’s how data is loaded in Martin’s QuadSampler patch that you’ve mentioned.

We don’t have a way to select them dynamically yet, even though it makes sense for a device with display like Magus/Genius. So for the time being you have to hardcode resource name in your patch statically, but of course any resource contents can be used with that name later.

1 Like

Thanks, so, I tried writing some code that uses Resources, and two things confused me…

First off, minor, Patch::getResource(), it says it “raises an error” if the resource does not exist…
Not sure what that means but it sounds bad. (EDIT: I tried it and when it prints the error it appears to terminate my patch! So that’s very bad…)
Is there a way to check if a resource exists before “getting” it?
I see if I call Resource::open or Resource::load open a nonexistent resource, it just returns NULL… should I be using those instead if I don’t know yet whether the file exists (because they return NULL instead of “raising an error”)?

Second off… I can’t figure out how to create a resource!
I tried calling new Resource(name, size, someData) experimentally to see if that would create a resource with the given size and resource, but that is protected.
Are patches allowed to create resources?

Well the error is the error message / status that you will get.

Yes

Currently you can’t write to flash from patches. It was implemented initially, but Martin decided against this due to flash wear concerns. So to write to resource storage you would have to store them in web UI or using FirmwareSender

Thank you for the help!

I’d be very curious if @mars could be convinced to reconsider on the patch saving.

[This] (NanoKontrol2Seq: 8 channel CV sequencing on Magus!) (see video) is the project I was hoping to make use of patch-side Resource save on. The idea is it uses the Magus to turn a particular midi controller into a sort of musical instrument/sequencer. You ear-tune up to 8 (maybe someday 16) CV values for each of (up to) 8 notes. Tuning all those values takes a long time and once you are done you obviously want to save your work! The sequences can’t be uploaded from the computer because they never existed on the computer, they were created entirely on the Magus. Connecting via USB to the computer and downloading them from there is probably a nonstarter(?) because while using the sequencer patch you want to MINIMIZE CV noise, and keeping USB HOST connected adds noise.

The inability to save sequences is made especially brutal by the known-issue bug where once USB DEVICE disconnects it cannot reconnect. In my experience with the patch so far, it is frequent that the nanoKontrol gets jolted and temporarily disconnects. But since disconnections are permanent now I must reboot the Magus, which means losing my sequence…

I understand the concern about flash wear. I am trying to figure out if there is some way to protect the device from aggressive saving. In the case of the sequencer patch, it currently saves only at the user’s request, so they at least know what they are doing to their flash…

One idea is maybe the patch uploader could have a checkbox for “allow patch side saving”, and Resource could deny saves to a patch if the user has not approved it. That might mean adding unaccessible complexity to the the patch uploader tho.

Hint: Martin’s been rarely available for last few months and this might not go further than just discussion.

I recall that the objections were specifically about writing to flash from user code (considering that this is controlled by somebody else when the patch is downloaded from the web). But I was told that triggering this from MIDI is probably OK.

Also, Witch has some kind of parameter persistence support, but I don’t quite understand how it works. I see that it has parameter loading, but nothing in firmware seems to store them. So I assume that the resource generation with patch settings is done somewhere in its web frontend. But we could do that in firmware too, i.e. there’s SAVE_SETTINGS MIDI CC defined that is not used for anything AFAICT.

Theoretically we have a few spare bits in resource header’s flags that could be used for something like this. But it only notifies users that patch will be writing to resources, not how many times it can happen. So the flash wear issue is still present.

We probably could just restrict patches to write to flash just once if it’s triggered by code.

Hm, like, CC 107 is sent, it saves? That makes sense, although I was hoping to implement in my patch something like, if you hold the REC button for 0.5 seconds it saves, if you hole CYCLE and hold REC for 0.5 seconds it reverts. That would be the friendliest version of the feature. And codewise that would probably still look like a save triggered by the patch…

So I am thinking about this from an end-user perspective… if a user has a sequencer, and there is a button in the sequencer to save their patterns, but the user can only use it once per boot up… that will feel illogical/unfriendly, and might lead to weird behavior like saving and then immediately rebooting the device. It might make sense from a system design perspective but less so at the user level for the kind of applications I’m thinking about…

Here is a question, you said this feature was in at some point. If I were willing to build my own firmware, could I dig that code out of the git history and patch it back in? Then I would only be ruining the flash on my own device… (Assuming I can get the firmware to build again of course.)

Sure, but it’s been a while since that was written and many things have changed. Here’s the initial version for resources support in firmware (+ some more commits from that branch) and patch side.

Note that:

  1. it also had some sort of indexing support - you could get number of resources and address them by ID to get names
  2. since then there was a big refactoring for flash storages to add support for external flash chip, some calls for saving resources are probably different
  3. it took 3 rewrites for this to be accepted upstream and I think Martin also made a few big changes to Resource class after that. IIRC only first version had write access.

This should give you an example of exposing parts of firmware to user patches via service calls. Ideally we would hear what @mars has to say about this, maybe there’s some approach that he would be willing to add to upstream.

1 Like