Is it possible that a hard fork of the source code might be easier to maintain?

AFAIK VCVRack is C++ too, a hard fork would mean you could take advantage of the C++ bits, and get rid of all the global variables, and generally not have to worry about maintaining compatibility between a microprocessor based C project vs a desktop CPU based C++ project.

5 Likes

amazing work. i’ll have to check out vcvrack now!

let me think over the brand issue for derivative works. my primary issue comes with user expectations of direct support for things i didn’t actually make.

but you’re absolutely not trampling, thank you for exploring this. curious to see how you did the shim layer when i get a chance to look at the code.

14 Likes

Speaking of VCV Rack, has anyone found a good place where discussions are happening about it? There are at least two Facebook groups, one official and one non-official, and a fairly un-utilized one at switchedonrack.com/forum.html. Thanks.

I’m in favor of starting a Lines general VCV thread. There’s a ton of noise on the Facebook groups, so it’s hard to keep up with everything.

This project is incredible. Excellent work, @Dewb.

10 Likes

Aleph codebase already has an avr32_sim library. It falls short of full hardware emulation. That always seemed like a tantalising prospect though - mostly just because flash cycles are quite long & I like using gdb when things explode. But for an aleph, full simulation is even trickier than for a eurorack module because the device has a DSP coprocessor (although we also emulate that to some extent). It’s still a lot of work to pull everything together, and I don’t think a VCV rack emulation of a full aleph would be that great a thing anyway. The main benefit of emulation there is dev tooling, and we already found more pragmatic solutions to the same problems.

I’m going to link our avr32_sim https://github.com/monome/aleph/tree/dev/utils/avr32_sim just because it already exists and allows us to run a fair bit of our avr32 firmware’s backend code on desktop. But don’t know whether or not it’s a helpful base to start from.

Anyway I’ll be watching your progress on this with some considerable interest!

EDIT:
also I spoofed the monome driver at higher level to hook into serialOSC in order to run bits of our firmware inside of puredata. This hack definitely comes highly recommended! (should solve your USB hotplug issues)

4 Likes

Coolness. I’ve initiated a VCV thread here:

4 Likes

A hard fork would have been a more straightforward way to start get one module into the VCVRack ecosystem. But it wouldn’t result in a workflow that would allow testing/debugging module firmware in a software IDE! Like I said, that’s my secret motivation here. I also didn’t relish the idea of reimplementing every single feature in WW, then starting over again from scratch with, say, Teletype. This strategy should hopefully be more maintainable than having to keep a set of hard forks up to date.

1 Like

Thanks! Completely understand re: user expectations.

The shim layer is really nothing special, it’s literally the simplest, dumbest thing I could make work as I went along. I have some ideas on how it could be generalized a bit into a C++ interface on the VCVRack side that calls a set of exported hooks from the cross-compiled firmware .dylib.

Oh nice, I did not know about the avr32_sim library! Will look it over, thanks. From a quick skim it seems like we had the same basic idea, with a few different choices on where lines are drawn, and yours is a lot more extensive.

Spoofing the driver and hooking into serialosc was something I considered – it means all module connections could go through serialosc, which would simplify things – but I think that’s orthogonal to my current hotplug problem. That issue is because I added hardware grid support really quickly once I got home on Sunday (didn’t bring my grid to the mountians with me, poor decision) and all I did was drop in daniel-bytes’ excellent serialosc C++ example code. I’m not handling any of the exceptions it throws on writing to disconnected ports, etc., hence the crash. Should be easy to fix.

1 Like

thank you for doing this! this is exciting on so many levels. allowing more people to use the module firmwares is great in itself, but i think this will also provide the incentive to keep them alive and developing further. of course, as a dev i’m most excited about being able to test / sketch ideas easier, i’m glad this is also your motivation.

i’m also hoping this will serve as an additional push for future firmwares to be developed in a manner that would make porting them to different platforms easier. one of the things i’m planning for the next version of orca is a rewrite that will separate hardware specific things for this exact reason. @sam did a lot of work of separating hardware bits in teletype too. emulating libavr32 is an interesting approach, haven’t considered that! (i need to check out avr32_sim).

11 Likes

The plugin now builds correctly on Windows, if that was holding anyone back from trying it out.

1 Like

That would be cool…, so long as you don’t end up with so many #ifdefs as to make the VCVRack version unrecognisable from the module version.

But it does throw up some ethical conundrums, IIRC there are only 100 of each of the trilogy modules in existence, there are bound to be many more users of the virtual version, which brings up the issue of support burden and new features (e.g. clock input for White Whale). At what point will the tail try to wag the dog!

I’m not suggesting you start from scratch, but make a fork of the existing code base with the intention that any changes you make to get it working in VCVRack are never ported back to the module version (that way it’s easy to add some extra inputs for clocking and pattern changing, etc, etc).

However, if you do want to keep with the shim layer (which would admittedly be very cool), one potential solution to the global variables issue that should require few changes in the module code would be for the shim to run it’s instance in a separate process (and thus separate address space) with an IPC to communicate between the child process and the parent.

The major downside is that it’s inherently not cross platform, so you need to find some sort of higher level wrapper. The plus side is that the same mechanism could be used to emulate the II bus…

Only on the “language” side alas, most of the UI code is very hardware dependent.

Adding a shim layer is a cool way to deal with an existing code base or if it’s purely for testing & development. If you’re starting from scratch though I’d humbly suggest that you put the abstraction layer much higher up. It’s something that C++ templates would have been good for, but I don’t think C++ is viable on the AVR32.

2 Likes

my plan is to separate the actual engine (so it will be essentially a completely hardware agnostic state machine) and then have a UI layer (which would be responsible for communicating with grid and in case of teletype, screen) and a hardware layer. the main module would be responsible for initializing everything and running timers/events queue, and should be hardware agnostic as well, except for the initialization part where it would plug appropriate instances for the UI and hardware layers. there will be another layer that would translate events (triggers, grid presses etc) into appropriate transitions for the state machine. for the UI i don’t think i’d want to use the event system (or maybe have a dedicated queue), but rather letting the state machine talk to the UI layer directly (for grids/arcs i think the existing libavr32 provides sufficient level of abstraction already). <- should probably start a separate thread for this!

2 Likes

Yup, it’s super super light. To better illustrate what’s going on, I reorganized the VCVRack plugin code so it’s in a separate repository. https://github.com/Dewb/monome-rack

Here are the only changes that have to be made to the whitewhale code: a few lines in main.c, and none in libavr32. One #ifdef to hide the flash NVRAM section attribute, and a slight change to how main() works, so the module init code can be called in isolation without entering the check_events() infinite loop. With the right inlining options, this might not result in any changes in the resulting firmware build.

2 Likes

Yeah, I totally get what you’re saying. Let me explain more where I’m coming from. I use white whale with a 256 (and @scanner_darkly’s 256 mods) and I perform with that setup every couple of months. Two of the three open issues for feature requests on WW are saving patterns to USB and treating the clock knob as a divider when the clock input jack is used. I would love both of those features and use them in performance immediately. I think I could tackle both, but I’m too lazy to do it if I have to debug blind with the hardware-load-test cycle, or take the module out of my rack to plug in some kind of ISP debugging interface. Now, though…

Making it easy to test these sorts of enhancements, and leveraging VCV Rack users as beta testers before things go to hardware, seems like an unambiguous win to me. The VCV Rack ecosystem is already pretty huge, if someone sees white whale for the first time and wants something from it that it’s not philosophically equipped to do, they’re just going to use another sequencer, I don’t think there’s much risk of a flood of orthogonal feature requests.

5 Likes

This sounds awesome! I’m excited to start poking around in the teletype code. I started with white whale because I was already sort of familiar with it, but teletype is obviously much juicier.

One more quote-response!

Oh certainly, an abstraction layer that’s much higher up (as @scanner_darkly describes) would be preferable. Hopefully things that are being actively developed can trend that way.

How the Mutable Instruments port was done is interesting. Most of the DSP and UI components are reusable C++, but for the VCVRack modules, the main loop of each module was rewritten inside the VCVRack class interface. This seems like 90% of the way there; changes to the base firmware DSP can be easily adopted in updates to the Rack plugin, but changes to the main loop would have to be manually analyzed and brought over.

C++ is totally viable on the AVR32. I’ve done a bunch of C++ on 8-bit AVR! C++ does give you a lot more dangerous toys to get into trouble with, but if you’re careful, it’s as efficient as straight C.

Olivier from MI also has two separate AVR abstraction layers using C++ templates:


2 Likes

Unfortunately, apart from the name, the AVR32 has little to do with an AVR8. I think the name was chosen for purely marketing reasons by Atmel.

The biggest issue with using C++ is that we’re stuck on GCC 4.4.7, and as C++ is a much more living language than C, that makes interoperability with code that targets C++11 onwards really hard. Also, and this is only anecdotal, but I think the AVR32 ASF code is not entirely C++ bug free. @zebra and @rick_monster might know more…

Ah, my mistake. Didn’t know that about the ASF and gcc limitations. I thought that all the Mutable stuff was on AVR, but on closer inspection the AVR ones are all Atmega644, the 32-bit modules use ARM Cortexes.

jumping in here cause i was tagged, and trying to follow whats going on… :slight_smile:
so, we are talking about potentially porting monome module code to vcvrack, which is a c++ project targeting win/mac/linux. okey dokey

and it has crept in that we do indeed have one layer of the aleph codebase compiling under c++ - namely the BEES application logic.

i’m not sure. sounds plausible. but the way we have dealt with it in bees is to avoid the ASF altogether.

originally, the hierarchy of components goes kind of like this:

1. ASF [lowest level drivers and stuff]
2. aleph/avr32_lib [aleph-specific boilerplate and drivers]
3. aleph/apps/bees [application logic]

we made avr32_sim a drop-in replacement for avr32_lib, using the same headers but replacing any calls to ASF functions. mostly its just placeholders.

since then, the modules were developed, and monome libavr32 was created from avr32_lib, and we just finished refactoring such that we now have

1. ASF [lowest level drivers and stuff]
2. libavr32 [common boilerplate and drivers for monome modules]
3. aleph/avr32 [aleph-specific stuff that wasn't included in libavr32]
4. aleph/apps/bees [application logic]

and now i think avr32_sim is probably a little bit broken…

but that’s just a limitation of the cross-compiler?

it seems like there are implicitly two different topics here:

  1. literally targeting the AVR32 hardware with c++. i agree that this is problematic for several reasons.
  2. targeting x86 with a c++ project that includes application logic from monome modules. i don’t see why this should be a problem. if the module project structure makes it difficult i think that’s an argument for refactoring the modules to make the application logic more independent and target-agnostic.

thought that all the Mutable stuff was on AVR, but on closer inspection the AVR ones are all Atmega644, the 32-bit modules use ARM Cortexes.

yeah, just to be clear when people say AVR they genreally mean AVR8 (atmega), AVR32 is more of an odd duck. kind of a relic of the time before ARM dominated the 32-bit RISC space, and unfortunately atmel has more or less stopped supporting it with new toolchains or libraries.

as sam says, avr and avr32 have very little in common apart from both being atmel products; avr8 continues to have low-cost, low-power applications and has received more support in the last 5 years.

i agree with this. if this were my project i would just focus on porting the core logic of each application…

1 Like