C++ dark magic of templating and constexpr

Continuing a little bit from my previous post. I was working on this Android thing that needs Java to be called from C++ and vice-versa, so I had to use JNI and as some might know JNI isn’t that beautiful to work with out of the box, so I was creating nice abstractions – like wrapping jobject in RAII class and make it possible to call methods on that object without always passing the JNIEnv pointer and also creating global references to use the object out of the function call scope etc.

As some might know calling a JNI method requires to pass the method signature which is this string that looks like this for an example: "(IJLjava/lang/String;)Z" where:

  • I stands for integer;
  • J stands for long;
  • Ljava/langString; stands for java.lang.String object;
  • and Z stands for boolean;
  • more on that here.

So every time you call a method you have to think of this string and also pass the apropriate arguments, but why not deduct the signature directly from the argument types passed in the method – of course it wouldn’t work for all the custom Java classes, but something could still be done about it … and so I got carried away.

First take – try to concatenate string by using recursive template argument pack unwrapping.

Basically this:

inline std::string get_signature()
{
    return {};
}

template<typename T, typename... TArgs>
inline std::string get_signature(const T& arg, const TArgs&... args)
{
	  return "x" + get_signature(std::forward<const TArgs&>(args)...);
}

All good – created a lot of special cases for each known JNI type and one special case for std::string -> java.lang.String.

The problem – Godbolt showed me a test case to be around 500 instructions – a lot of things to happening at run-time – mostly string construction and concatenation – which is not what I’d like to happen on every method call.

Take two – reuse single std::string with pre-reserved memory.

inline void get_signature(const std::string&)
{}

template<typename T, typename... TArgs>
inline void get_signature(std::string& out, const T& arg, const TArgs&... args)
{
	  out.append("x");
	  get_signature(out, std::forward<const TArgs&>(args)...);
}

Things start to look better – Godbolt shows reduced instruction count to 200 – still a lot of run-time calculations are happening, but at least there’s no unnecessary re-allocations.

Still I thought to myself – I can do better.

Take three – the dark arts of constexpr.

I thought – could it be possible to run all these concatenations at compile-time? I reverted back to first solution and switched to C++20 in hopes to invoke std::string constexpr constructor and hoped the concatenation operator would work too – turns out compilers are not all there yet.

Then I found this wonderful C++17 example on StackOverflow and that helped me achieve this:

inline constexpr auto get_signature()
{
    return concat("");
}

template<typename T, typename... TArgs>
inline constexpr auto get_signature(const T& arg, const TArgs&... args)
{
	  return concat("x", get_signature(std::forward<const TArgs&>(args)...).str);
}

This reduces everything down to near zero instructions as the string get’s concatenated at compile time. How cool is that?

So in the end I can have this abstraction for JNI method call:

template<typename... TArgs>
inline void invokeMethod(const std::string& method, const TArgs&... args)
{
	constexpr auto signature = get_signature(std::forward<const TArgs&>(args)...);
	jniEnv->CallVoidMethod(method, signature.str, std::forward<const TArgs&>(args)...);
}

which reduces this:

javaObject->invokeMethod("doSomething", "(IJLjava/lang/String;)V", 1234, 987654321L, "asdf");

into this:

javaObject->invokeMethod("doSomething", 1234, 987654321L, "asdf");

Not much, but dope AF!

Master’s degree in Computer Engineering

So, I finally did it, I’m graduating from university for the second time. The first time was 12 years ago when I got myself a master’s degree in Physical Chemistry, now it’s time to tie up some loose ends and get a degree in what I’ve been doing professionally for the past 14 years – Computer Engineering.

This time I’m so proud of my work in my master’s thesis that I’m willing to share it in public, so here it goes:

Abstract

In today’s live music performance a computer has become one of the music instruments on stage, but unfortunately it might become a cumbersome factor because of it’s universal nature. As an alternative this thesis researches processor architecture and operating system combinations for running virtual music instrument and virtual sound effects applications on specially developed embedded hardware for live music performances.

The research was done on two different devices with programs running on Linux operating system and directly on processor (bare metal). The main criteria for the research were – the ease of use of development tools, processor performance of floating point calculations and power consumption with an aim to use the device with battery power.

Conclusions were drawn that with today’s relatively cheap embedded hardware devices it’s possible to run virtual music instrument software, these devices boot up fast enough and they can perform long enough on battery power to use them for live performances on stage.

ARCHITECTURE, VST, DAW, EMBEDDED HARDWARE, MUSIC INSTRUMENTS, SOUND EFFECTS, DIGITAL SIGNAL PROCESSING, SOUND SIGNAL SYNTHESIS.

And finally…

So where to next? If that would be possible, I’d look into opportunity to wire a joint doctor’s thesis in chemistry and computer engineering, but we’ll see …

Analog Devices CrossCore Embedded Studio on macOS using Lubuntu

Continuing from my previous how-to post, today I’d like to show you how to develop on Analog Devices hardware using CrossCore Embeded Studio on macOS. As it is with most of these types of sofware – they run on Windows and sometimes (if you’re lucky) they’ll have a Linux version. In my case I wasn’t 100% lucky, as the Linux version does not run quite perfectly on virtual machine.

Prerequisites

  1. VirtualBox
  2. Lubuntu LiveCD
  3. Analog Devices CrossCore Embedded Studio (this one you can download inside the virtual machine)
  4. Windows virtual machine (I used one downloaded from modern.ie)

Prepare virtual machine

After installing the VirtualBox and downloading Lubuntu LiveCD, go and create a new virtual machine with at least 40GB of disk space (you’ll actually need less than that, but it’s always safe to have some legroom).

Mount the LiveCD and install the bare minimum Lubuntu with GUI. After installing the Lubuntu, open the web browser inside it and download CrossCore Embedded Studio.

Installing CCES

Installing CCES is pretty straight forward, just install the deb package using:

wget http://download.analog.com/tools/CrossCoreEmbeddedStudio/Releases/Release_2.8.3/adi-CrossCoreEmbeddedStudio-linux-x86-2.8.3.deb
cd ~/Downloads/
sudo dpkg -i adi-CrossCoreEmbeddedStudio-linux-x86-2.8.3.deb

It will be installed under /opt/analog/cces/2.8.3/.

Unfortunatelly CCES is based on Eclipse (requires Java) and is 32-bit only, so you’ll have to install a few more dependencies by hand to make it work:

sudo apt install lib32z1 lib32stdc++6 lib32ncurses5 openjdk-8-jre:i386 libswt-gtk-3-java:i386

Now you can run the CCES by running:

/opt/analog/cces/2.8.3/Eclipse/cces

Installing license

This is the tricky part – unfortunatelly CCES can’t install license on Lubuntu – it fails with error “validation code has expired” even after entering a valid serial and all the registration data. It also can’t do the e-mail validation and effectivelly won’t add your serial number to license manager. Don’t worry – I found a workaround – use Windows. Bare with me…

You’ll need to do following:

  1. Download Windows on a VirtualBox disk image (I used modern.ie for that purpose with Windows 10 disk image)
  2. Before launching the image change it’s network adapter’s MAC address to match the one used in Lubuntu (Go to Settings -> Network -> Advanced) as CCES uses MAC address to tie the activation to your computer.
  3. Launch Windows, install CCES, activate CCES using your serial number.
  4. Now you’ll have to copy the license.dat file from C:\ProgramData\Analog Devices\CrossCore Embedded Studio\license.dat to your Lubuntu ~/.analog/cces/license.dat – easiest way is to copy it through shared clip-board, because license.dat is just a text file. Just mind that on Windows it has CRLF line endings whereas on Linux it’s LF only.
  5. Get rid of Windows.

Use CrossCore Embedded Studio

When all that is done, you’re ready to write your DSP stuff on a macOS in a virtual Linux, just pass throuh [the device] to the guest machine (Go to Devices -> USB -> [device]) and you’re good to go.

Poll: OSS and Proprietary license mashup?

Law is one hell of a programming language, you as a developer will always have trouble understanding it and the lawmakers will always have trouble understanding development processes.

I wanted to ask you about OSS licenses and their usage in proprietary software and vice-versa. We have very many great OSS licenses, like GPL, LGPL, BSD, MIT, MPL, ASL, etc. But what is that area they cover in development terms and what are you allowed to do with this software?

Continue reading Poll: OSS and Proprietary license mashup?