Sunday, September 23, 2018

Pitch Calculation and Output

"If pitches were horses, we'd all be eatin' steak." --Jayne Cobb
And where have I been for almost two months? I was busy. For one thing, I was busy at my actual job where they pay me actual money to write actual code. And when I wasn't doing that, I was working on the last couple releases of Hemisphere Suite.

For each release of Hemisphere Suite, I like to focus on a theme that explores some aspect of electronic music. 1.3 was the MIDI release, 1.5 (coming Sept. 28) will be the Shift Register release, 1.6 (coming Oct. 26) will be the <no spoilers!> release. 1.4 was the scales release. It had several projects that required me to really learn how O_C handles pitch output through its DAC functions. For anybody who wants to do Ornament and Crime development, this is an important topic. I mean, I did okay without this knowledge for a while; but then, when I figured some things out, I had to go back and redo some of my work, to make pitch output more accurate. So best to pass that info along.

The DAC Function


Way back in June, I talked a bit about how the ADC class had several different functions for getting ADC input. Well, it's sort of the same with the DAC. If you take a look at OC_DAC.cpp and OC_DAC.h, there are a few functions to choose from.

For my work, I've settled on one function to use for everything (see OC_DAC.h):

static void set_pitch(DAC_CHANNEL channel, int32_t pitch, int32_t octave_offset)

I'm sure the others have their uses. Actually, I'm not sure about that at all. I never met a job that set_pitch() couldn't do. Anyway, within your code, a call looks like this:

OC::DAC::set_pitch(channel, pitch, octave);

The parameters are as follows:
  • channel is an enum with the values DAC_CHANNEL_A through DAC_CHANNEL_D. It specifies the O_C output whose CV output is being changed.
  • pitch is a value that corresponds to voltage. Exactly how it corresponds to voltage is something we'll talk about under the next header.
  • octave_offset raises and lowers the octave by this many octaves. It's also basically a voltage offset.
I've got a couple notes on set_pitch() for you:

It can only be called outside of the menu function. If you're drawing the screen, you can't access the I/O, and vice versa. Doing either type of operation in the wrong place will crash the module.

The channel must have the type DAC_CHANNEL. If you want to use an integer (0-3) to access a specific output, you'll need to use a cast. I've just used C-type casts for this purpose:

int ch = 1; // Channel B
DAC_CHANNEL channel = (DAC_CHANNEL)(ch);
OC::DAC::set_pitch(channel, value, octave);

Also, note that when set_pitch() sets the pitch, the output stays at that level until it's changed. You don't need to keep refreshing the output during every ISR cycle.

What is "pitch" for OC::DAC::set_pitch()?


Pitch is a bipolar value, where 0 means 0 volts. Negative numbers represent negative voltages, and positive numbers represent positive voltages.

One octave is equal to 12 << 7. That's 12 semitones times 128 (or, 2^7), or 1536. You can also read that as "one volt is equal to 12 << 7."

One semitone is equal to 128. 128 is therefore 1/12 of a volt (or about .0833V). This means that each increment of pitch is 1/128 semitones (or, .78125 of a cent) or 1/1536 of a volt (or, about .00065V).

The output range of O_C is said to be between -3V and 6V. This means that pitch has a practical range of -4608 ~ 9216.

Given a CV value (perhaps from an ADC, or sequencer, etc.), you can get octaves and semitones like this:

int cv = <some CV source>;
int octave = cv / 1536;
int semitone = (cv % 1536) / 128;

You can likewise convert a CV value to voltage like this (note that the O_C's M4 doesn't have a hardware floating point unit, so do whatever conversions you need to do):

int cv = <some CV source>;
float volts = cv / (12 << 7);

I know that's a lot of stuff to remember. The good news is, you don't need to remember it. Everything I just told you about the value of pitch can be derived from a single piece of information:

one volt = 12 << 7

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.

Pitch Calculation and Output

"If pitches were horses, we'd all be eatin' steak." --Jayne Cobb And where have I been for almost two months? I was busy...