Thursday, August 2, 2018

MIDI Part One: MIDI Out

It's easy to forget that the USB jack on the back of an Ornament and Crime can be used for things other than updating firmware. Teensy 3.2 has a capable, if poorly-documented, MIDI library. With the right software, O_C can be a modular system's link to the outside world.

I'm going to walk through sending MIDI messages in this post. In the next post, I'm going to introduce Captain MIDI, a full-scale modular MIDI interface in the classic Ornament and Crime style.

Enabling MIDI


MIDI support is enabled in Arduino IDE as one of the compile options. From the Tools menu, go down to "USB Type" and choose "MIDI" instead of the usual "No USB."

Note #1: MIDI support adds about 3% to the size of the compiled binary, so if you're working with a normal O_C codebase, MIDI support might take you over the limit.

Note #2: I haven't tested the default O_C apps with MIDI support enabled. I think they'll continue to work as normal, but I haven't tried it.

Note #3: Arduino IDE remembers your last settings. This is usually a good thing, but it means that you'll need to keep track of whether you want MIDI support enabled or not if you have multiple codebases.

Note #4: When I compile with MIDI, I don't have to push the Program button on the Teensy; programming starts automatically as soon as the build is done. I don't know why it works this way, but I suspect that it's normal USB behavior that is suppressed when compilation is done with "No USB."

The Teensy USB MIDI Library


See the Teensyduino USB MIDI documentation here:

https://www.pjrc.com/teensy/td_midi.html

The information on that page can be characterized as somewhat accurate. Hopefully, I can save you from some of the frustration that I experienced when I counted on it being right. Still, it's a decent starting point, and it's worth knowing.

If you go through the library code that's part of Teensyduino, there's more than one MIDI library, so I suspect that the documentation just wasn't updated. At very least, it's not specific to the Teensy version that we care about, 3.2.

But the documentation's gaps won't vex us too much for Midi out. It'll become more relevant when we look at MIDI in.

Basic MIDI Out


I'm starting with MIDI out because it's a bit easier than MIDI in. Don't worry, MIDI in is still pretty easy. But with MIDI out, you're just using the documented methods to send messages.

Every MIDI operation (out and in) uses the global object usbMIDI. For example, to send a Note On message, you do

usbMIDI.sendNoteOn(midi_note, velocity, channel);

midi_note is an integer from 0-127, velocity is an integer from 0-127, and channel is an integer from 1 to 16. Take note that MIDI channels in this library are 1-indexed.

The MIDI library puts each message in a buffer, and holds onto it until 16 messages have been buffered, or until 1ms (or so) has elapsed, whichever comes first. If you want to send buffered messages earlier than that, you can call

usbMIDI.send_now();

Note Off is similar to Note On, including velocity:

usbMIDI.sendNoteOff(midi_note, 0, channel);

MIDI control change looks like this:

usbMIDI.sendControlChange(controller_number, value, channel);

Note that value has a seven-bit range from 0-127, per the MIDI specification.

usbMIDI.sendAfterTouch(value, channel);

This is channel aftertouch, and the value here is also from 0-127.

And pitch bend:

usbMIDI.sendPitchBend(bend, channel);

The bend range here is from 0-16383. Values from 0 to 8191 are negative bend, 8192 is 0 bend, and values from 8193 to 16383 are positive. For logging purposes, I'd just display (bend - 8192).

Other MIDI Out


I've been working with system exclusive messages, and I'll probably deal with that separately if anyone is interested. I haven't really figured out clock yet. The documentation says this:

usbMIDI.sendRealTime(usbMIDI.Clock);

but there is no usbMIDI.Clock, at least for Teensy 3.2, and there doesn't seem to be specific support for clock in the library code. So this is sort of on my "pending" list. The library lets us construct MIDI messages a byte at a time, and that might be necessary if we want clock.

Wednesday, July 25, 2018

Spoiler Alert: A Hemisphere Suite 1.2 Preview

Hemisphere Suite 1.2 will be released on Friday, July 27th. My plan is to add new applets fairly regularly through the end of the summer; but Friday's release goes a little beyond that, with some fairly big changes to the framework itself. So I wanted to introduce those changes a little before the release.

As always, the hex file will be available here: https://github.com/Chysn/O_C-HemisphereSuite/releases.

The Help Screens Are Moving


I didn't like the way the Help Screens worked. You had to long-press the left encoder, then long-press it again to go to the next hemisphere, then long-press it again to get back to the main screen. All this long-pressing was inelegant.

I've introduced a double-click action to the Up and Down buttons. It's pretty much like double-clicking a mouse button, expecting about a half second between the first press and the second press. The Help Screens are now activated with a double-click of the corresponding button (Up for left hemisphere and Down for right). Once you're at a Help Screen, you can simply click same button again to get out of Help, or click the opposite button to see the other Help Screen. You can switch back and forth this way as many times as you like.

The Help Screens still have no effect on an applet's operation, which was an important consideration for me. Applets still function, and you can still control them in the blind.

Help Screen Video (YouTube)

Clock Forwarding Is Moving


I wanted the Up/Down buttons to centralize operations having to do with applet management, so I moved the Clock Forwarding control to the left encoder, where the Help Screen control used to be. In all other respects, it's exactly the same.

Clock Forwarding Video (YouTube)

Category Filtering Is Coming


At about 30 applets, it started becoming kind of annoying to flip through them all. So Hemisphere Suite 1.2 introduces a category filtering system, which allows you to restrict the types of applets you see.

To enter the Categories Screen, first activate Selection Mode by clicking on the Up or Down button. Then, long-press the Down button. When you release it, the Categories Screen will be displayed in the selected hemisphere. Use the corresponding encoder to choose a category (they are, off the top of my head, Modulator, Sequencer, Quantizer, Clocking, Utility, MIDI, Audio, and Other) or ALL. Then press the corresponding Up or Down button again.

Now, when you scroll through available applets in that hemisphere, you'll see only applets assigned to the chosen category. Each hemisphere can have a different category selected. These categories are not remembered when state is saved.

Category Filtering Video (YouTube)

I hope you all enjoy the new features! The dust should be settling on the interface after this. Hemisphere 1.2 has some new applets, too, including a Burst Generator and Comparator,

Friday, July 20, 2018

Hemisphere Suite 1.0

I'm happy to announce the release of Hemisphere Suite 1.0. It's available as a hex file at

https://github.com/Chysn/O_C-HemisphereSuite/releases

I'm consolidating everything to GitHub, so the documentation is also there, with detailed information about all 24 of Hemisphere Suite's applets, and The Darkest Timeline sequencer app. And Pong. I had to throw in Pong.

https://github.com/Chysn/O_C-HemisphereSuite/wiki

I spoke before of releasing Hemisphere Suite with a limited number of original O_C apps, but I decided to call an audible on that idea and remove them all. So Hemisphere Suite is sort of aimed at people with multiple O_Cs.

Thursday, July 12, 2018

A Small Hardware Project: The O_C Programming Panel

For the first time since I bought my Ornament and Crime, it is fully-racked in my case with four screws. It will no longer spend most of its time propped up by a USB cable at an awkward 45-degree angle.

I cut into my case this evening and added an Ornament and Crime programming panel. It consists of a Switchcraft USB jack, a momentary push button, and a short USB cable for inside the case. Here's the panel in progress:

The Switchcraft jack has a USB Type B jack on one side, and a Type A jack on the other side. So all I had to do was connect a six-inch USB cable into my O_C's Teensy. To maximize its life span in there, I cracked open a brand new Teensy.

The button is to put the Teensy into programming mode, and it just connects to Program and Ground
terminals near the Teensy's on-board button. Here's the O_C hooked up:

I had to swap the positions of my O_C and my Varigate 4+, because the internal USB cable takes a lot of space to the left of the module, and it can no longer go up against the edge of the case. Fortunately, Varigate 4+ is really slim, and the cable has plenty of clearance below the Varigate 4+.

I'd prefer to have the O_C on the left edge, but I'll learn to like it this way. I'll keep my eyes open for a short right-angle USB cable. I've seen them right-angle, and I've seen them short, but....

Anyway, here's what the programming panel looks like from the back, once everything was back together:

This simple thing is going to save me lots of time that I've been spending hooking up the stupid USB cable and fishing around for the stupid tiny little button.

Wednesday, July 11, 2018

Checking In, and a Slight Course Correction

I've been busy with the Hemisphere beta releases, and really busy at my actual day job, and haven't had time for the blog. Sorry about that. So for those readers among you out there, I wanted to quickly bring you up to speed on upcoming projects.

This Blog


This blog was originally intended to be a journal about how to develop O_C apps. But I think I'm pretty much at the end of the line there. First of all, it doesn't seem like that's something that other people are really that interested in. I knew it would be a small audience, with the hobby of developing applications for a specific eurorack module buried under several nested layers of "niche." But second, I've pretty much covered the topic. Anybody that wants to write an app for O_C can get a pretty good start with the information here, and I don't have that much more to say about it.

On the other hand, the topic of the software that I'm producing is up one or two levels of "niche," and there's a relatively strong level of interest in it.

So, this blog will shift a bit toward my own O_C projects, of which there are many. I'll discuss code where it's appropriate or (mildly) interesting. And I might wind up doing more development tutorials if there are any requests, or I find a topic I've neglected.

Hemisphere


The first version of Hemisphere is in what I hope is its final beta release. If no more bugs are found, it'll be released with a version number on July 16, 2018. After this, I plan to merge any new O_C operating system updates into the Hemisphere release.

This release keeps Ornament and Crime apps, with the exception of Meta-Q. So it's basically O_C + Hemisphere and 13 applets. This configuration takes up all of the O_C's program storage, so the plan is to go into a stable release that won't change much over time.

Hemisphere Suite


This is my current project. For the multi-O_C crowd, this removes the O_C apps to make room for many applets and new full apps. This will be rapidly-changing system and will contain everything that I do. There will be some weird stuff in there, but hopefully pretty interesting.

At the moment, it includes a slew processor, a gated VCA, a port of an accent sequencer I wrote for Peaks called Palimpsest, a playable implementation of John Conway's Game of Life, and a dual Euclidean drummer called Annular Fusion. I'm also planning to update the Hemisphere framework with a master clock forwarding mode, so that both hemispheres can share a single clock source.

Documentation


This is important, and I can't neglect it. I have to document the applets' functions and keep the documentation somewhere. Right now, information is kind of fragmented between this blog, GitHub, MuffWiggler, and my website. I need to consolidate. So that's a thing, too.

Neural Network


The neural network full O_C app is also in active development, although right now it largely involves research. So more to come on this as it comes together.

Messing With My Case


I got this awesome Switchcraft flush-mount USB jack. When I get some time, I'm going tear my system down and install the jack and a button, so that I can program my O_C without it hanging out of the case. I'll post photos, at least!

Tuesday, July 3, 2018

Hemisphere Beta Release PFAQ

PFAQ? Potentially Frequently-Asked Questions, because I haven't been asked any questions yet. But I'm looking for synthesists who are interested in trying alternate firmware for Ornament and Crime, and providing bug reports and feedback.

When is the release?


July 4, 2018, at www.beigemaze.com

How will it be released?


A Teensy hex file is available at http://www.beigemaze.com/hemisphere.html.

You can install with the instructions at http://ornament-and-cri.me/firmware/#method_a.

This is a beta release. I'm looking for people who'd like to try Hemisphere and provide feedback. You should be comfortable installing firmware, and optionally reverting back to the previous version if you want to return your O_C to its factory state. It's not a difficult process, but unfortunately I can't hold your hand very much.

Will I lose any data saved in my O_C?


Yeah, it's a pretty safe bet that you'll lose everything saved in your O_C. This isn't something you want to do just before a show.

Will I lose any apps?


The native Ornament and Crime firmware pretty much takes all of the Teensy's memory. So I had to free up about 20K by disabling Meta-Q in this release.

Do I have to be part of the beta, or can I just download Hemisphere and install it?


When the hex file is released, you can just download Hemisphere and install it without participating in the beta. But it's all going to be pretty informal anyway. I won't be asking beta testers to follow any particular procedures or use bug tracking software. The best place to talk about the beta will probably be right on this here blog page.

Is it finished?


There's always room for improvement, but there are 14 applets available now. These are:
  1. Dual Quantizer - Selectable scales, continuous or clocked operation
  2. Dual Clock Divider/Multiplier - Two divider/multipliers share a single clock, from 1/8 to 8/1
  3. 5-Step Sequencer - 2 1/2 octaves, quantized to semitones
  4. Dual 8-Step Trigger Sequencer - Edit steps in groups of four, with adjustable length
  5. Sample and Hold with Random - One is a conventional S&H implementation, the other side is a clocked random source, with the option for both sides share a single clock
  6. Dual Calculator (arithmetical operations) - Sum, difference, min, max, average, and ranged random
  7. Dual Logic (boolean operations) - AND, OR, XOR, NAND, NOR, XNOR, with the option to put the operator under CV control for both channels
  8. Threshold Logic Neuron - Generate complex but deterministic clocks or states; this is how they thought the brain worked in the 1950s
  9. Two-Channel Gated/Sequential Switch - Switch between two voltages with a gate signal and/or a clock
  10. Probability Brancher - Switch between two voltages for each clock pulse, based on a set probability
  11. Skewed LFO - From saw to triangle to ramp, add a little simple modulation
  12. Dual ADSR - This
  13. Lo-Fi Tape Looper - One second. 8 bits. 2kHz. Go!
  14. Gated VCA - Sort of a two-level VCA, accepts a signal, modulated by CV, and unleashed with a gate... or not, your call
There's a YouTube video going over the functions of each module at https://www.youtube.com/playlist?list=PLC5d4vp670NsuEUQybeCPYOvoDJb9fnBi.

There will be more apps in the future, but to make space on the O_C for more, I'll have to do a full release that removes most of the native O_C apps.

Monday, July 2, 2018

Tutorial: Working with Menus, Buttons, Encoders

Way back in the Hello World post, like three weeks ago, I promised that I'd cover menu generation. Since then, I've decided that my own apps wouldn't use menus. But, you know, a deal's a deal, and using O_C's native menu generation system is an important part of development.

In this post, I'll be referring back to the last tutorial, about saving app settings. The reason for this is that the menu system dovetails very nicely with the setting system. The work that you do to declare data types, ranges, potential values, and names of settings also goes toward generating the menu pretty much automatically. If you need to whip some CV processing up quickly, but don't want to mess around with building UI from scratch, you're in luck.

Please pull the Tutorial repo at the usual place, and follow along in the new APP_LOGIC.ino file.

The App


The application is a simple 4-channel logic app. Each channel takes input from two digital inputs, processes it with one of six logic gates (and, or, xor, nand, nor, xnor), and outputs the result to the corresponding channel.

For each output channel (A, B, C, D), the user chooses a logic gate operation and selects which digital inputs are used for the calculation. The selection follows conventional O_C functionality: the right button switches between selection of the parameter and editing, while the right encoder scrolls through the parameters or selects values. The underlying framework asks you to code the functions of the controls, but the data management and screen handling (switching, scrolling, etc.) is handled for you.






Step 1: Set up the enum containing the settings

Don't want to dwell on the first step too much, because we've seen this stuff before. The enum is a list of labels for settings, with a last setting marker:

enum LOGIC_SETTINGS {
    LOGIC_SETTING_OPERATION_A,
    LOGIC_SETTING_SOURCE_A,
    LOGIC_SETTING_OPERATION_B,
    LOGIC_SETTING_SOURCE_B,
    LOGIC_SETTING_OPERATION_C,
    LOGIC_SETTING_SOURCE_C,
    LOGIC_SETTING_OPERATION_D,
    LOGIC_SETTING_SOURCE_D,
    LOGIC_SETTING_LAST
};


See also the LOGIC class definition, which uses the SettingsBase parent class.

Step 2: Set some value lists


In the last tutorial, I used settings strings from OC::Strings. This time, I'm defining my own settings strings, which will be displayed on the screen and used in Step 3:

const char* const gates[6] = {
  "AND", "OR", "XOR", "NAND", "NOR", "XNOR"
};

const char* const input_pairs[3] = {
  "1,2", "2, 3", "3,4"
};


Step 3: Declare the settings


In the last tutorial, the settings declaration was only used to identify what would be saved. This time, the declarations will actually be used for displaying and validating menu values, so it's important to set ranges and names up as you want them to function:

SETTINGS_DECLARE(LOGIC, LOGIC_SETTING_LAST) {
    { 0, 0, 5, "Logic Gate A", gates, settings::STORAGE_TYPE_U8 },
    { 0, 0, 2, "Source for A", input_pairs, settings::STORAGE_TYPE_U8 },
    { 0, 0, 5, "Logic Gate B", gates, settings::STORAGE_TYPE_U8 },
    { 0, 0, 2, "Source for B", input_pairs, settings::STORAGE_TYPE_U8 },
    { 0, 0, 5, "Logic Gate C", gates, settings::STORAGE_TYPE_U8 },
    { 0, 0, 2, "Source for C", input_pairs, settings::STORAGE_TYPE_U8 },
    { 0, 0, 5, "Logic Gate D", gates, settings::STORAGE_TYPE_U8 },
    { 0, 0, 2, "Source for D", input_pairs, settings::STORAGE_TYPE_U8 }
};


Step 4: The Cursor


menu::ScreenCursor<menu::kScreenLines> cursor;

You'll provide this as a public property in your app's class somewhere. Some native apps put it in a struct. The idea is that it needs to be available, because it handles lots of stuff, as we'll soon see.

In this case, it's in the LOGIC class, and will be referred to via logic_instance as logic_instance.cursor. If you want to hide it in a private property and create a getter for it, knock yourself out.

Step 5: Initialize the cursor in Init()


This tells the cursor which parameter to start with (from the enum generated in Step 1), and which parameter to end with. For a simple menu, you can just provide the starting and ending points of the entire list of settings. But your app may have different needs.

void LOGIC_init() {
    logic_instance.cursor.Init(LOGIC_SETTING_OPERATION_A, LOGIC_SETTING_LAST - 1);
    logic_instance.Init();
}


Step 6: Drawing the menu


To draw the menu, create a SettingsList and then iterate through its available() method until you've reached the end of the settings. The pattern below will get you a conventional O_C menu, and you really don't need to do much else, other than provide logic that might show or hide settings conditionally. But you don't need me for that.

void LOGIC_menu() {
    menu::DefaultTitleBar::Draw();
    graphics.print("Logic");

    menu::SettingsList<menu::kScreenLines, 0, menu::kDefaultValueX - 1> settings_list(logic_instance.cursor);
    menu::SettingsListItem list_item;
    while (settings_list.available())
    {
        const int current = settings_list.Next(list_item);
        const int value = logic_instance.get_value(current);
        list_item.DrawDefault(value, LOGIC::value_attr(current));
    }

}


Step 7: Setting the button and encoder behaviors


You should have some idea about how to handle button and encoder events, as this topic has been covered in the Pong Game tutorial. However, looking back, I sort of glossed over that, so we'll talk about it a bit here. First, here's the button event handler:

void LOGIC_handleButtonEvent(const UI::Event &event) {
    if (event.control == OC::CONTROL_BUTTON_R) {
        if (event.type == UI::EVENT_BUTTON_PRESS) {
            logic_instance.cursor.toggle_editing();
        }
    }
}


Whenever a button is pressed, and the screensaver is not active, the APPNAME_handleButtonEvent() function is called, passing a UI::Event reference.

An Event has a few readable properties, two of which are relevant to button presses:

event.control: Indicates which button was pressed. OC::CONTROL_BUTTON_R and OC::CONTROL_BUTTON_L are the encoders, and OC::CONTROL_BUTTON_DOWN and OC::CONTROL_BUTTON_UP are the up/down buttons next to the screen.

event.type: Indicates whether the button was pressed (UI::EVENT_BUTTON_PRESS), or long-pressed (UI::EVENT_BUTTON_LONG_PRESS). Note that a long press of the up button activates the screensaver, and a long press of the right encoder goes to the app selection menu. These events will never be intercepted by an app because they are overridden by the framework.

In the handler above, when the right button is pressed, it toggles the editing mode of the app instance's cursor, between parameter selection and editing. You don't need to do anything special to handle the new state.

Encoder handling works in a similar way:

void LOGIC_handleEncoderEvent(const UI::Event &event) {
    if (event.control == OC::CONTROL_ENCODER_R) {
        if (logic_instance.cursor.editing()) {
            logic_instance.change_value(logic_instance.cursor.cursor_pos(), event.value);
        } else {
            logic_instance.cursor.Scroll(event.value);
        }
    }
}


Here, the event.control is set to either OC::CONTROL_ENCODER_R or OC::CONTROL_ENCODER_R, indicating which encoder was turned.

Instead of event.type, an encoder event's behavior is read with

event.value: Indicates whether the encoder was turned clockwise (1) or anti-clockwise (-1). The O_C system has the ability to fire multiple encoder events when the encoder is turned fast. Your code doesn't need to worry about this. You can just assume that you're handling changes one increment at a time.

The handler above checks the cursor.editing() mode to decide what to do. In editing mode, it changes the value at the cursor position. This is nice and automatic: it checks the appropriate range (from SETTINGS_DECLARE() in Step 3) and updates the values in the app class.

If editing mode is off, it scrolls through the menu items. Again, you don't need to specifically handle the scrolling. The cursor and SettingsList (Step 6) handle all that for you.

That's it for today!

A Word about Hemisphere


It was nice to see the support of the Hemisphere project. The Hemisphere introduction dwarfed readership of the next most popular post by over 5,000 views. At this point, Hemisphere is ready for beta testing. So if you'd like to try it out, let me know by IM'ing me at MuffWiggler (I'm chysn) and I'll send you a link to the hex file.

In the coming days, I'll be producing a series of one-minute videos, one for each applet. That rollout will be my next blog post.

MIDI Part One: MIDI Out

It's easy to forget that the USB jack on the back of an Ornament and Crime can be used for things other than updating firmware. Teensy 3...