Introduction to Juce
Juce is a GPL-licensed library for writing C++ software. "Juce" stands for "Jules' Utility Class Extensions," as it was written by one person, Julian Storer. Capitalization of its name doesn't seem to matter—we've seen it written as "Juce," "juce," and "JUCE" in official documents.
At the start of development, we considered a number of open-source, cross-platform libraries, including Qt, GTK+, FLTK, wxWidgets, openFrameworks, GLUT, and Clutter. After experimenting with each, Juce emerged as the best of the bunch.
Advantages of Juce
- Completely open-source, which allows us to tweak the library as needed
- No licensing restrictions for non-commercial applications
- Intuitive class structure based on components
- Completely cross-platform so we can compile the same code for Linux, Windows, and Mac
- Extremely lightweight, which allows us to include the source code in our GitHub repository.
- Great documentation
- A very helpful forum, where you'll often get help from Jules himself
- Built-in audio processor classes, which make it easy to set up processing pipelines for ephys data
Disadvantages of Juce
* Only one available tutorial. However, the Juce package contains example applications that cover almost every aspect of the library.
* It's not as widely adopted as Qt, which means you can't purchase Juce books or find extensive online examples. However, we have found Juce's online documentation and forum to be more than adequate for learning and troubleshooting.
How to acquire Juce
Because the entire library is so compact (less than 13 MB), we've included it in the GUI repository. Therefore, if you clone the repository, you automatically download a copy of Juce. If you want the application to run, you NEED to use this version of Juce, as some methods have been customized (see details below).
The library files contained in this repository are based on Juce version 4.2.1. If you want to check out the original source, you can download a .zip file from GitHub. In addition to the source code, this package contains example applications that are useful for gaining familiarity with Juce.
Audio processing in Juce
The Juce library was originally created to build audio processing applications, and thus it includes well-developed classes for manipulating audio data. As you'll see in the Juce forums, most of the people using Juce are building audio apps and plugins. Why does this matter for the GUI? As it turns out, the steps involved in acquiring, processing, and storing audio data are profoundly similar to those required for electrophysiological signals. Using Juce's built-in audio classes with very little modification has made it surprisingly easy to build a sophisticated processing pipeline for neural data without worrying about the nitty-gritty details of buffering, message passing, and threading. Therefore, many classes used in this application have "Audio" or "Midi" in their name. Neural data processors are derived from the Juce AudioProcessor class, continuous signals are stored in AudioSampleBuffers, and spike events are sent in MidiBuffers. At some point in the future, it may be prudent to build a custom backend for data handling, but for now, Juce's audio classes have made the development process much faster without any noticeable detriment to performance.
Here are some Juce classes that are used extensively throughout the GUI. You should learn to love them:
- AudioSampleBuffer - used to shuttle continuous data through the ProcessorGraph. Holds an array of floats of size channels x samples.
- MidiBuffer - used to shuttle event data through the ProcessorGraph. Holds discrete events with a timestamp and several bytes of data. In the Juce source code in this repository, the MidiBuffer class has been modified so that each event can hold an arbitrary number of bytes. This is so things like spike events can be sent from processor to processor through the MidiBuffer.
- Component - almost everything the user can interact with is a component. Components hold other components as children, which inform their parents when they receive a user input, such as a click.
- Graphics - used to draw within Components.
Changes to the Juce source code
As mentioned above, you should be aware than the Juce source files included in the GUI repository are not identical to those obtained directly from GitHub.
For Juce version 2.0 and higher, we made the following changes to send spikes as MIDI messages:
- `MidiBuffer::addEvent` in `modules/juce_audio_basics/midi/juce_MidiBuffer.cpp` was modified to handle MIDI events of arbitrary length (lines 143-160). This allows spikes and other event-based data to be passed between processors via the MIDI buffer.
- `MidiMessage::getMessageLengthFromFirstByte` in `modules/juce_audio_basics/midi/juce_MidiMessage.cpp` was changed to return the input (i.e., it no longer checks to see that the message length is less than or equal to three bytes.
- The assertion on line 121 of `modules/juce_audio_basics/midi/juce_MidiMessage.cpp` was commented out.
- The "if" statement on line 406 of `modules/juce_audio_basics/midi/juce_MidiMessage.cpp` was commented out, to allow the second byte of a MidiMessage to be set to zero (for saving purposes)