Sunday, June 27, 2010

A Close Look at Thor's Shaper


Quick Links

Thor's Shaper is a modest device - it sits nonchalantly between Filter 1 and the Amplifier module and to me it was shrouded in a certain mystery. The Reason Operation Manual doesn't give much away, mentioning it briefly on page 215:


"Waveshaping is a synthesis method for transforming sounds by altering the waveform shape, thereby introducing various types of distortion. The Shaper can radically transform the sound or just add a little warmth, depending on the mode and other settings.

There's a brief mention of how to use it, and the names of the nine modes it supports, but that's about it.

I thought it might be useful to take a closer look at the Shaper and see if I can determine what it actually does.

First, a few things you need to know about the Shaper.
  • the Shaper has to be enabled to do anything interesting, obviously.
  • only Filter 1 output can go into the Shaper - the manual says:
"You can also route other sources directly to the Shaper in the Modulation section."
    but this is not correct. The Thor modulator destinations only include "Shaper Drive", and not the Shaper audio input. If you want to direct anything into the Shaper, you need to direct it into the Filter 1 audio input, and then typically select Filter 1 Bypass to disable any filter that is there.
  • the Shaper will not do anything until you trigger a "voice" in the synth. This means hitting a note on your keyboard when Thor has controller focus, using the sequencer to play notes through Thor, or using the Step Sequencer to allocate a continuous voice by latching the Step Sequencer trigger and setting the gate length to 100%.
  • the "Drive" control can be used to change the effect that the Shaper has on the sound. It can be set to a specific value or modulated by the Mod Matrix. A signal can also be routed directly into "Shaper Drive".
  • typically you'll use it to shape audio, but you can also use it to shape CV signals as well.
  • Thor has a bug.
So what does the Shaper actually do? Simply, it shapes or distorts the incoming signal according to the mode selected and the Drive setting. In most cases, the distortion is non-linear.

It is important to understand what non-linear distortion means. To do that, let's talk about linear systems first.

Linear & Non-linear Systems

A linear system is essentially (yes, I'm going to keep it simple) one in which the output scales proportionally with regards to the input. This means that if you have one input signal and you double its amplitude, you will see the output signal double too. If you have two input signals and you add them together before putting them into the system, then the output you see will be the same as if you put each signal into the system independently and then added the outputs. This is called the principle of superposition.

Linear distortion, where a signal is altered by a linear system, is pretty common. Essentially, you multiply the signal by a number so it's either larger (amplified) or smaller (attenuated). Static filters such as low-pass filters with an unchanging cut-off are examples of such distortion. Certain frequencies are cut out or boosted by amplifying or attenuating those frequencies. I'm deliberately ignoring phase effects mmmkay? :)

This leads to an important aspect of linear systems - you can only get out an amplitude- (and phase-) modified version of the frequencies you put in. If you put in a sine-wave at 100 Hz, you can only get a sine-wave at 100 Hz out, although it might be louder or quieter than the input.

A non-linear system on the other hand is an entirely different beast. The easiest way to define such systems is to simply consider them as systems that are not linear! In all cases, the output is disproportional to the input or inputs. This means you might put in 100 Hz and get out 372 Hz, or put in 100 Hz at one amplitude level and get an output that modulates amplitude over time.

Most systems in real life are non-linear but engineers prefer to think in terms of linear systems because they are a gazillion times easier to analyse. In many situations a complicated non-linear system can be broken down into a number of simpler, linear systems and analysed to a certain level of accuracy.

Thor's shaper is a non-linear system, but it's a relatively simple one. It contains no dynamic internal state so there's no time-based distortion effects. The shaping is simply done by a non-linear function selected by the Shaper Mode. Unfortunately it's not easy at all to reduce this to a simpler set of linear systems, but we can still learn a lot by looking at its behaviour.

Linear & Non-linear Functions

Consider the function f(x) = x/2, or y = x/2, which looks something like this:

(thanks Wolfram Alpha)

Consider an input signal of some value "x" - look along the horizontal x-axis for the value x, move straight up until you hit the diagonal line, then move directly across to read the corresponding output on the vertical y-axis. It's fairly straightforward to see that this function divides all incoming signal values by 2 - it always halves the amplitude of the input signal, regardless of what the actual input is. This is linear distortion.

What about this function, y = x2?


This is a parabolic function - the output is not proportional to the input signal, but to the input signal squared. Look at x = 0.5, the output is 0.25. The signal is attenuated by a factor of 2. When x = 1.0, the output is unchanged at 1.0. So the amount of this attenuation depends on the input value. Therefore the output is disproportional to the input signal - this is non-linear distortion.

If the function goes through the origin (where the axes meet), then that means that an input value of zero produces an output of zero. This has implications for zero-frequency (DC) offset that I might talk about later.

Thor's Shaper implements nine different functions in this manner, but also provides a "Drive" parameter. This parameter simply affects the shape of each function in a particular way - for one mode it might change only part of the function slightly, in another mode it might result in a completely different function altogether. Since there are 128 possible drive settings, you could consider there to be 128 different functions for each Shaper mode.

With this in mind, now I'm going to introduce and explain each mode and how the Drive parameter affects it.

Shaper Modes

In the following sections, for each mode, you will see two plots. These are screen shots from Audacity of signals generated in Reason and distorted by Thor's Shaper. Each plot has nine waveforms - these are measurements of the Shaper at various Drive levels from 0 to 127 - 0, 16, 32, 48, 64, 80, 96, 112 and 127.

Each waveform is independent of the others - it's just easier for me to present them on a single axis. Zero on the horizontal axis is in the centre of each waveform (where the diagonal line crosses the axis in this case). Zero on the vertical axis is where the horizontal axis lies.

The first plot will be a representation of the Shaper function, obtained by passing a rising full-scale linear signal (sawtooth) through the Shaper and recording the output. This is essentially just reading out the values in the function look-up table (if Thor uses such a thing). In this example, the Shaper is turned off and output is directly proportional to the output - in fact it's the same, or y = x:


If the function is linear, then the output will look exactly like one of the graphs above. In this example only, all nine waveforms are practically identical because the Drive parameter has no effect when the Shaper is disabled.

The second plot is an example of what the Shaper does to a pure sine-wave input for each drive setting:


Because the Shaper is switched off in this example, the function is again y = x and the sine-wave is unmodified regardless of the Drive parameter. For other modes it's interesting to see the effect on the sine-wave but its usefulness is limited - remember that the Shaper is non-linear so you cannot apply the principle of superposition! Adding sine-waves together before the Shaper input does not give you the same result as adding the result of passing through separate sine-waves. A particular function might generate a harmonic for a single sine-wave input, but two sine-waves might do something else entirely - see Intermodulation Distortion below.

In all cases, you can click on an image to view a full-resolution version.

I used these RNS files to generate the signals by "exporting loop as audio":

WARNING
For the CV Scope, the connection from the main mixer to the hardware device is deliberately disconnected. Do not reconnect the audio output unless you have turned off your speaker system first! I am not responsible for any damage that might result if you try to drive CV signals through your expensive amplifier or speakers!!



Soft Clip

function

sine-wave

This is a simple distortion that reduces the range of the incoming signal as the drive increases by clipping the signal. Compared with the hard clip, there is a more gentle, rounded characteristic to the clipping. Note that at zero drive it is not quite linear - there's a small distortion in linearity and a small attenuation of amplitude. At high drive the distortion is very distinct, very similar to the hard clip mode, and will introduce many new frequencies.

sine-wave chord



Hard Clip

function

sine-wave

This is a very simple and nasty type of distortion that simply limits the input signal to a maximum and minimum level according to the drive. It is similar to the soft clip mode except that the function has no gentle rolling off before the clip takes effect. At zero drive, the function is practically linear, and at maximum drive it's pretty much a step function except for a very narrow range near zero, just like the soft clip at this drive. This distortion adds significant new frequencies at higher drives.

sine-wave chord


Saturate

function

sine-wave

It is my understanding that the saturate mode is meant to model the behaviour of a transistor that is fully turned on. There is a linear section near the origin, but as the signal approaches the upper and lower limits, the saturation function pulls it back in. It's essentially a smoother version of the soft clip, which means it puts less energy into the higher harmonics.

sine-wave chord


Sine

function

sine-wave

This is a weird one - the shaper function is actually a sine-wave itself. I'm not sure what the intent of this function is, but it's pretty strange. At low drive, it's a bit like saturate with an attenuation at extreme input values. At higher drives, the frequency of the 'sine-wave' increases rapidly, essentially producing what I'd consider to be a fairly random effect. Consider an input signal value of x, with a drive of 127 - the output value is going to be almost anything, and will change dramatically for very small changes of x. It's pretty unstable.

This mode has some interesting and dramatic results if you automate the drive control, so that it changes as the sound plays through the shaper.


sine-wave chord


Bipulse

function

sine-wave

Another slightly strange distortion mode - I imagine it's called "bipulse" because at higher drives the function looks like two pulses, one inverted. Notice that the output signal for any input is greatly attenuated for any drive setting - even at minimum drive, the signal is no more than 25% of the original amplitude. At lowest drive, it's very similar to the sine or saturate function. As drive increases, the attenuation becomes even more dramatic. It's as if the signal almost disappears. I'm really not sure what I'd use this function for, but if you put in a very quiet signal, you would get an amplified output, whereas louder inputs would tend to disappear to nothing.


sine-wave chord


Unipulse

function

sine-wave

Yep, another unusual function. This is actually an even function, which means that it reflects negative input signals back into the positive half; notice the sine-wave above, it never goes below zero. In many ways, this function is a bit like a soft clip followed by a rectify - at low drive, it rectifies and amplifies then clips the input signal. At higher drives, the clip level decreases and the amplification domain becomes very small. At maximum drive this mode essentially creates a fixed DC signal and not much else.


sine-wave chord


Peak

function

sine-wave

The peak mode has two main effects - first, it cuts out all positive input input, which reduces the energy in the output by half. Second, it clips the negative input. So it's really just a soft clip or saturate with the bottom half cut off.

One unexpected use of this mode is to implement a unipolar step function for CV processing - at maximum drive, the output is zero for negative CV (0-63), and -64 for positive CV (64-127). All you have to do is invert this and you've got a nice step function.

sine-wave chord


Rectify

function

sine-wave

Now we're getting interesting - this function has some interesting properties. At zero drive it's linear, and at low drive the bottom is attenuated. At mid-drive, the lower half of the input signal is zeroed out and energy is lost. At higher drives, things get very interesting - the lower half is mirrored up into the top half, and this has three effects - first, fundamental frequency is doubled; second, the fundamental frequency is eliminated; third, even harmonics are introduced.

You can also use this function with CV processing to zero-out half of the input signal by setting the drive to 63. Unfortunately, the function is not quite zero for negative CV input, so you don't get a pure zero. An inverted peak works better in this case. The advantage is that this function retains linearity for the upper half of the input signal domain.

sine-wave chord


Wrap

function

sine-wave

And now for the strangest function of them all. I'm really not sure how to describe this one. At low drive, it's linear, but as the drive increases the upper half of the input signal is quickly attenuated non-linearly, and then inverted! Yet the maximum positive input is still passed through unmodified. As drive increases further, it just gets weird. Look at the way it distorts a basic sine-wave. Crazy stuff!

sine-wave chord



Frequency Analysis

I set out intending to examine each mode according to its frequency response. But I quickly hit a problem - non-linear systems don't lend themselves to frequency analysis very easily at all. Since the usefulness of this analysis is very limited, I decided to give this a miss.


Audacity does do some very nice spectrum analysis plots though.


Intermodulation Distortion

Intermodulation (wikipedia) is a phenomenon of non-linear systems where two input frequencies combine in a way that does not produce harmonics, but typically sum and difference frequencies. It's essentially an interaction between the input signals - they mix together and produce new frequencies which are typically non-harmonic, or "off-key".

This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License.

It's intermodulation distortion that makes non-linear systems difficult to analyse, as well as sometimes sound very cool. It also means that the sine-wave plots throughout this article are indicative only - simply add a second sine-wave and you'll get completely different results. Put in more complex signals and who knows what you'll get out...

As I was writing this, something occurred to me. If you take a typical Thor sound patch and play a chord, Thor creates a separate voice for each note. Each voice has its own Shaper, so you're only playing one note through each Shaper - the result is mixed together later. This completely avoids any intermodulation distortion created by different notes. If you want to create this sort of distortion, which sounds completely different, you need to route the mixed audio into another Shaper. Here are some examples of the same chord played through a separate Shaper:

soft clip
hard clip
saturate
sine
bipulse
unipulse
peak
rectify
wrap

Here's the RNS file:

Using the Shaper for CV Processing

Normally the Shaper is used for audio distortion, but with a few considerations it can also be used to process CV signals. This opens up some very interesting possibilities.

Shultz designed a Triple Cross Fader using the Shaper's rectifier mode. This brilliant design uses the drive set to maximum which implements two piece-wise linear functions. You can read all about this here.

During the development of my 8-bit Adder, I encountered an issue where one of my CV signals was growing very, very large. This was causing the Thor scaling to fail. To fix this, I fed the rogue CV signal into a Thor Shaper with the hard-clip mode set to zero drive. This clipped the CV signal at 127 rather than whatever high value it had reached, and this allowed the Thor scaling to work properly again, regardless of what processing happened before.

In order to use the Shaper for CV processing, there's a trick you need to know. Because the Shaper is located in the "per-voice" section of Thor, it is only available when Thor is playing a note. Or at least when Thor thinks it is playing a note.

To do this, route your incoming CV source into Filter 1 Audio Input, then route the Shaper output to wherever you want the output to go. The trick is to use the Step Sequencer on Repeat Mode with a single step of gate length 100%, and to tie the Step Sequencer Trigger to LFO2, set to square wave. Also, set LFO2 to trigger the Amplitude Envelope (with A=99ms, D=max, S=max, R=max). The LFO2 rate and Step Sequencer rate don't seem to matter too much (but see the bug below).


I've created a basic template for this here.

The Bug

I co-discovered an unfortunate bug in Reason 4. Although the above self-triggering of the Step Sequencer works fine after loading a file, sometimes after exporting an audio clip, or even hitting "stop", the Thor Step Sequencer stalls. The 'Run' light remains on and the Step Sequencer is running - you can see the lights flashing above the steps - but there's no output. To reset this condition, simply click the Thor Run off then on. You can set the gate length to 99% to avoid this problem, but this will introduce very obvious glitches between each step. Not good.

This bug is a bit of a shame really, because it's just serious enough to make the Shaper unreliable. To get around this, I am considering making all of my Shaper devices 'resettable' - an external signal will toggle the trigger. Then I just need a way to generate this signal on "stop" - this same behaviour can be exploited to do this, as long as this behaviour remains consistent in future versions of Reason... (*ahem*).

Update: selig has suggested an excellent workaround for this bug here, using the global LFO2 to trigger a voice's Amplitude Envelope. I have created an updated template here and the old one is still available here. This design solves the "stop" bug, but still has an issue after exporting audio. The fast LFO2 rate retriggers as soon as possible. If you don't care about the export issue, you can turn down the LFO2 rate if you like.

Using the Shaper as a Standalone Effects Device

The Shaper is a mono device - it can only process a single audio channel at a time. However you can use it to process any audio, not just Thor's oscillator signals. With this in mind, and using the same principles as the CV Shaper above, you can use the following patch to do this - just wire your incoming audio into Audio In1, and take the result from Audio Out1.
If you want to process a stereo signal, just use two of them.

The Random Element

The Reason manual mentions that the Shaper has a slightly random element:
"... there is a slightly random element to the resulting distortion."
I'm not sure what this refers to. During my analysis the shaper functions were very well defined and always returned the expected values. I did notice a couple of glitches (if you look carefully you may see them in the plots above) but I put these down to Step Sequencer glitches briefly disabling the shaper. Other than that, I didn't see anything random at all. Maybe someone at Propellerhead can enlighten us?

Spiky Glitch

One other observation - sometimes the first value that is fed into the Shaper for each 'scope' sweep outputs an extreme low value. You'll see this as a little downward spike in the function graphs above, on the left, just as each one starts. I wasn't able to determine what causes this - I'm not even sure if it's a consequence of "exporting to audio file" or whether it's either related to the way the Step Sequencer works, or behaviour of the Shaper when it is given a zero input for a period of time. Any ideas?

Conclusion

This might be the longest article I've written for this blog so far - it certainly took the most time. Hopefully, if you've read this far then you now have a better understanding of what Thor's Shaper actually does in each of its modes.

In my opinion, the effect that the Shaper has on many sounds is a bit unpleasant, although with care it can be used to add warmth. It should work differently on chords because of intermodulation, but by default a separate instance is used for each note/voice, so you have to route into a Shaper yourself.

I don't think it's quite as pleasing as the Scream4 but it is a handy device to have around and its use in CV processing is also very powerful.

If you have any comments or questions, please do submit them - it's always great to get feedback.

Saturday, June 26, 2010

Akai MPK49 Pad Modification

A few years ago I did a light review of the Akai MPK49 MIDI keyboard controller. Subsequently I bought one and I've been happily using it since.



However one thing consistently bugged me (and everyone else) about the design - the drum "pads" are terrible. You have to hit them quite hard to even register a hit, let alone a loud one. Because I'd never really used such pads before, it didn't bother me too much. But Kong is coming...

So when I saw these two threads on the Propellerhead User Forum, I knew I had to give this a try. I'm really glad I did.

This video is a nice guide on how to take the MPK49 apart and get access to the rubber pads. There are 28 screws to remove, but it's not very difficult. The video author does a good job showing how to get inside, so I'm not going to rehash that here.


Some things to remember while taking apart your precious MIDI controller:
  • use a manual screwdriver rather than a motorised one as in the video - take note of how much torque is required to unscrew those twenty rear-plate screws, and when you put back together again, do not tighten them up any more than that. You're screwing into plastic - you do NOT want to strip the threads!
  • also try not to cross the threads when you're putting the screws back in, or you'll risk stripping the threads.
  • when you remove the little PCB, watch out for that little 1-inch ribbon connector. It's not too fragile I suspect, but try not to pull on it if you can.
  • when removing or replacing the rubber pads, be careful not to damage or scratch the underlying sensor array. I don't know exactly what it is (PVDF perhaps?) but it looks delicate.
  • when you replace the outer case, be careful not to trap the ribbon cables that might stick out the back.
 
The fundamental problem with the pads is that there is a gap of approximately 1mm between the bottom of each pad and the pressure sensor underneath. This means you have to hit or press the pad hard enough to travel that 1mm before any pressure will be sensed, regardless of the pad sensitivity settings within the MPK49. It doesn't matter how sensitive you set the software within the keyboard to be, that gap is always going to be a problem.

The simple solution is to fill the gap up with something. Many people, including that video, recommend using four layers of electrical insulation tape underneath the rubber pads. But electrical insulation tape? Really? I hate that stuff! After a while, the adhesive oozes out and goes everywhere, it's horrible, horrible stuff. Avoid!

Instead, I decided to use some cloth tape, sometimes rightly or wrongly called "duct tape", or occasionally "gaffer tape" (although mine isn't black nor has it a matte finish). The nice quality about this tape is that the adhesive is pretty stable and doesn't migrate much, but it's also pretty sticky. It's also quite robust and for this application it should hold its thickness over time.

I didn't know how much I'd need initially so I put a strip onto some grease-proof baking paper and ruled out 15mm x 24mm rectangles. The baking paper made it really easy to cut the tape to the right size and then peel it off for application without contaminating the glue with dust or clothing lint.


I started off with just a single layer on a single pad. I reinstalled the rubber pads and gave it a try. The improvement was considerable - in fact I was very tempted to leave it at that. But of course I'm not one to take something apart without trying out a few things...

So I tried two layers. This was even better! I could now do cool drum rolls with my fingers and I wasn't constantly 'missing' the pads and sounding incompetent.

Once again, I was going to leave it at two layers, but just to make sure I tried out a few pads with three layers.




Wow! The improvement is dramatic! I barely have to exert any pressure on the pads at all to get a decent signal, yet I don't get spurious hits either. Three layers is definitely where it's at in my opinion.

But three layers of the tape I've got doesn't mean much to anyone else, so I measured it for you.


Without going into the gory details, I ascertained that the tape is approximately 0.3mm thick, and I used three layers, so that's a total thickness of 0.9mm, with an error of, let's say, +/- 0.05mm. When you look at the underside of the rubber pads end-on, you can see the top layer of tape just below the edge.

(I used the coin as a known thickness to measure inside the pad cavity - the coin is 2.15mm thick on the edge, I measured 8.05mm without tape, and 8.97mm with three layers of tape. This is about 0.3mm per layer.)

Once you've put it all back together, you can set the pad sensitivity, threshold and curves to whatever you want. I'm using threshold 1, sensitivity 16, curve A and it seems to work fine.

The Akai MPK49 is a great but not perfect keyboard. If you have one, I definitely recommend doing this mod - it's not hard, just take your time and think ahead. In total it took me about an hour with all the measuring, experiments, etc.

Bring on Kong!



Friday, June 18, 2010

Digital Logic in Reason: 8-bit Full Adder


On the Propellerhead's Users Forum, user fieldframe likened my 16-bit counter to a calculator that some clever person had implemented in the successful PS3 game "LittleBIGPlanet":


It was a very generous comparison - I'm sure that person spent a lot longer than I did on their amazing creation. I'm not going to go to such extraordinary lengths to do anything like this in Reason. Well, not for a little while anyway, but it did give me the idea to implement a simple 8-bit adder.
This article contains some introductory explanations of digital logic - you may already know some or all of this, but if you don't then I hope you find this informative.

An 8-bit adder takes two 8-bit binary numbers, and adds them together to give a result. For example, 85 (01010101b in binary) summed with 60 (00111100b) gives 145 (10010001b). I'm only concerned with unsigned numbers in this article.

The heart of the classical digital adder is the 1-bit full adder - a relatively simple device that takes three digital inputs and produces two digital outputs:
  • A and B are single bit inputs representing the two 1-bit numbers to be summed ("addends")
  • input Cin is a single bit input that is usually tied to zero but can accept a carry overflow from a previous adder unit when multiple adders are chained together.
  • output S is a single bit output that is the binary sum of A and B.
  • output Cout is a single bit output that is high if the sum resulted in a carry.
This image is used under the Creative Commons Attribution ShareAlive 3.0 license.

This device is combinational rather than sequential or synchronous because it makes no use of internal state - there are no flipflops or clock signals. Everything happens as soon as the inputs change. A counter is (usually) a sequential circuit - it has internal state (the current count) and that only changes when the clock rises. Generally, sequential circuits are much more interesting than combinational circuits, but you need working combinational circuits to create interesting sequential circuits, so for this project I'm concentrating on creating a robust combinational device.

Quick aside: A OR B (inclusive OR) means (A or B) or (A and B), whereas A XOR B (eXclusive OR) means (A or B) but not (A and B). i.e. one or the other but not both.

A 1-bit Full Adder outputs:
  • S as high if A and B are different and Cin is low, or A and B are the same and Cin is high. i.e. (A XOR B) XOR Cin.
  • Cout as high if either A & B are both high, or (A XOR B) and Cin are both high.
The schematic for this circuit can be drawn as:

By placing multiple Full Adders together side-by-side with their Carry inputs and outputs connected it is possible to create a wider Full Adder, such as this 8-bit one:


This image is derived from this source and distributed under the same Creative Commons Attribution ShareAlike 3.0 license.

Each bit of addend A (A7..A0) goes into a separate 1-bit Full Adder along with its counterpart from the other addend B (B7...B0). The result is simply the collection of outputs S (S7...So). However, in the event that this eight bit result overflows, the last carry Cout will be set, so the result is essentially a nine-bit number Cout + S (CoutS7...So).

This is essentially the way I've constructed my 8-bit adder, which you can play with here.



For the purposes of my demonstration, to set the 8-bit inputs A and B the following section in the rack is used:



Each input has two combinators associated, with buttons labeled 0 to 7. These represent the bits within the 8-bit input number. Each bit in an unsigned binary number has a weight dependent on its position. Button 0 is the least significant bit with a weight of 1, and 7 is the most significant bit, with a weight of 128. The value of a binary number is the sum of the weights for positions where a 1 appears and these eight buttons can be used to set this. Therefore the buttons represent the ones and zeros in an 8-bit unsigned binary number.

For example, the following represents a digital 0 input:


00000000b = 0*128 + 0*64 + 0*32 + 0*16 + 0*8 + 0*4 + 0*2 + 0*1 = 0

Whereas this represents 71:


01000111b = 0*128 + 1*64 + 0*32 + 0*16 + 0*8 + 1*4 + 1*2 + 1*1 = 71

And of course this represents 255:


11111111b = 1*128 + 1*64 + 1*32 + 1*16 + 1*8 + 1*4 + 1*2 + 1*1 = 255

By setting up A and B, you'll see the sum on the "A + B" Vocoder near the bottom. This example shows 85 + 60 = 145:


01010101b + 00111100b = 10010001b

This example (255 + 1 = 256) shows what happens when the eight bit sum overflows into the final carry output, and becomes nine bits:

11111111b + 00000001b = 100000000b

So how did I construct a 1-bit Full Adder? Look at the schematic diagram again:


You'll notice that the device is made up from two XOR gates, two AND gates and an OR gate. I already have these from my 16-bit counter project, so I can simply wire them up here (after fixing a minor bug in the AND gate):




Because I was able to implement two XOR gates and two AND gates in a single Thor instance, I only need three Thor devices (XOR2, AND2, OR2) to implement this adder. Cool. But what's that fourth Thor for?

It turns out that in Reason, CV signals are not limited to the operational range 0-127. It appears that, with Thor at least, it is possible to go beyond these limits to some degree. As the value gets bigger it eventually reaches a point where the Thor "mod scaling" fails if it uses this value. Normally an input signal of zero scaled by a CV value of 127 gives zero, but if the scaling factor is high enough it seems that Thor's multiplication goes a bit nuts and zero times a large CV value is some other large CV value. This causes the AND gate to fail - you get: (low AND high) gives "high", which is wrong.

In this application, there are four upstream logic gates (Thor instances) that contribute to the Cout signal and this seems to push the CV value too high when all the inputs are high. So the final Thor is used to hard-limit the final Cout output to the range 0-127, using the hard-clip mode of Thor's shaper with minimum drive. Therefore the nasty large CV value is squashed back into the expected 0-127 range and everything downstream works properly again.


The shaper buffer.

For a bit of fun, this is what part of the back of the rack looks like once everything is wired up:



:)

After all that, what use is this adder? Well, for one it helps validate my logic gates - the more things like this that work, the more confidence I have that my designs are working properly. Secondly, with a few changes, this will be the basis for a subtractor, which will then allow me to differentiate a CV signal, which is a measurement of the signal's slope at a point in time. This opens the door to CV integration, where CV signals can be integrated over time by simply keeping a running sum. This is essentially the same as measuring the area under the curve. Integrators and differentiators are an important part of many circuits, including feedback systems, so perhaps I can find some musical use for this yet.

Of course, if you have any good ideas, please let me know or feel free to try building something yourself with the files and ideas I've shared.

For reference, I include my combinational logic gate test-bench (version 0.0.4) - bipolar NOT, XOR, AND and OR gates for your use. Enjoy.

Files in this post:

The examples in this article require Reason 4 or newer.

Sunday, June 13, 2010

Digital Logic in Reason: Updated Flipflop & Counter

Thanks to everyone here and in various other places for the great feedback on my 16 bit counter. I completely appreciate that this 'invention' is somewhat esoteric at this point - it's not even obvious to me what one might actually use it for. However I do have some ideas brewing and that's led me to slightly refine my flipflop slightly.



The new version (0.0.3) has more consistent assignment of the input and output ports, with a "pass-thru" output port for each of the three (clock, reset, data) input signals. The signal on the input port simply appears on the output port, immediately and unchanged. This allows you to easily chain together multiple flipflops without having to create large banks of CV splitters.

The main state or "Q" output has been moved to CV Out4. The mandatory wire between Audio Out1 and Audio In1 remains - remember that you have to add this manually since it is not saved as part of the .thor patch.

The "beep" button can be used to help debug the operation of the flipflop - to use this, connect a wire from Audio Out4 to a mixer channel, then click the "beep" button and you should hear a beep on each rising clock edge. The tone changes depending on whether the Q output is high or low.

To demonstrate that this flipflop still works, I have included a test-bench and an updated version of the 16-bit counter. Both use version 0.0.3 of the flipflop throughout. I've also included the 4-bit counter combi patch.

I have yet to analyse the setup- and hold-times for this device. The internal 7.9ms delay will definitely limit the maximum speed that this device can run at. If I used an external DDL-1 I could reduce the delay to 1ms but that would mean either putting the entire device inside a combinator (which I want to avoid for as long as possible), or ensuring an external DDL-1 is hooked up to every flipflop.

There was also a slight bug in the AND2 device - this has been fixed in the files above (bipolar and2-0.0.2).

Stay tuned for more digital logic posts.

The examples in this article require Reason 4 or newer.

Monday, June 7, 2010

Synchronous Digital Logic implemented in Reason 4

Updated - Digital Logic in Reason: Updated Flipflop & Counter

Correction - FF pass-through outputs are CV Out3 and CV Out4 (not 2 & 3) for clock and reset respectively. The diagram is incorrect for version 0.0.1.




This is the sort of post where you either understand what I'm talking about, immediately realise the huge implications and your brain explodes, or you don't know what I'm talking about, in which case none of this will make much sense.

Late last year, I spent a considerable amount of time working on an idea. I wanted to see how far I could get implementing some sort of "digital logic" with Reason4 devices. You know, the sorts of things that make computers and electronics work. I wanted to use CV as a kind of "voltage" and create both combinational logic gates (e.g. AND, XOR) as well as sequential logic (flipflops) so that I can combine them to create various complex devices such as finite state machines or digital adders. This is the sort of thing that electronics engineers like myself think about...

I had grand plans for this stuff, but time ran out for now. Therefore I'd like to post what I have to date so that people can pick this up and run with it if they think it's interesting.

I did manage to get things working quite nicely - I believe basic finite state machines are definitely possible and to prove this I created one of the most simple of all - a counter. Behold, my 16-bit digital synchronous counter implemented entirely with Reason devices!



This design is based on the standard synchronous counter implemented with D-type flipflops, as described here.


Schematic.

In order to achieve this, I had to design a suite of simpler devices such as AND and XOR gates, as well as synchronous elements such as a clock generator and a flipflop.

I set myself some goals:

  1. each device must compose of no more than a single Thor instance. No combinators allowed because I wanted to put groups of these devices inside combinators without messing around with combi programming.
  2. ensure the devices are designed to run at the fastest Reason CV oscillator rate - 250 Hz. Not very fast really, but fast enough for what I want to do.
  3. ensure that the flipflops act as registers, not latches. The output should only change on the 'clock edge'.
An important question I had to resolve is whether to use unipolar (0-127) or bipolar (-64 to 63) CV signals as representations of digital logic levels. After a lot of messing around with unipolar CV, I eventually gave up and tried bipolar CV instead. It was much easier and this is what I'm now using. If anyone is interested, here are some unipolar combinational logic gates, but I failed to construct a reasonable flipflop.

Bipolar input signals need to be specially constructed, so I designed a bipolar signal source and bipolar clock generator to produce the right CV signals.

I'm not going to go into the intricacies of the combinational logic devices, but here is an interactive testbench (RNS). Click the Thor buttons labeled A, B, C and D to generate logical input signals...



then select your function from the Function Select combi (only choose one at a time!).




You should see the result in the Outputs combi. Some devices incorporate multiple gates, and are named as such - e.g. AND2. In this case, inputs A & B correspond to output W, and C &D correspond to output Y. For the NOT4 device, A corresponds to W, B to X, C to Y and D to Z.



You should be able to verify these basic logic operations pretty easily with this testbench.

The flipflop (FF) is a much more interesting device, and is the fundamental building block for synchronous logic. I won't go into the details of an ideal D-type flipflop, but one characteristic that is crucial is that the output only changes on the rising clock edge (i.e. when the clock transitions from low to high, in this case).



This testbench shows a single flipflop in operation. The clock is running at about 1 Hz and you can hear and see this in the Monitor combi. You can change the clock rate with knob 1 on the Inputs combi. You'll also see four buttons:


  1. reset - used to set the FF into a known state - set the button for at least one clock cycle, then unset it. It is a synchronous reset.
  2. data - the input signal that the FF will sample on the rising clock edge and hold.
  3. enable - used to turn the clock on or off. This version of the clock generator does not implement this correctly.
  4. beep - simply for audio feedback, turn it off if you prefer.

Below, the MONITOR combi shows four button-lights. The "FF Output" is the critical signal, and it should change to whatever "data" is set to, but only when the clock goes from low to high (i.e. just as the CLOCK button lights up).



The FF has 3 inputs on the back panel:
  1. ROTARY 1: incoming data that will be sampled and held on the rising clock edge.
  2. CV In1: the clock signal - a bipolar CV signal in the shape of a square wave.
  3. CV In2: the reset signal - active high, synchronous, sets the FF output to low.
The FF has several outputs:
  1. CV Out1: the sampled and held output.
  2. CV Out3: simply a pass-through for the clock for chaining FFs together.
  3. CV Out4: simply a pass-through for the reset for chaining FFs together.
  4. Audio Out4: this is for an optional 'beep' sound that helps debug the FF operation. You can leave this disconnected.

Correction - pass-through outputs are CV Out3 and CV Out4 (not 2 & 3) for clock and reset respectively. The diagram above is incorrect.

NOTE: when you save a Thor patch, it does not save any rear-panel cables. For the FF to operate correctly, you must connect AUDIO OUTPUT 1 to AUDIO INPUT 1 with a single cable.



This FF works by using a little trick to store state information. The incoming data value is used to set the transpose level of the Step Sequencer. However Thor will only remember this value when the Step Sequencer is triggered by the clock incoming on CV In1 going high. If we stopped here, there would be a problem. The FF output must only change when the clock edge rises, so it must not be transparent to changes on the data input when the clock is high. I forget exactly how I solved this, but I end up converted the stored value (transposed note value) into an audio signal, passing it out of the Thor via a very small delay, taking it straight back in again and converting it to an output CV value. This also creates a very short propagation delay that prevents the FF output from changing simultaneously with the clock edge - if it did, then downstream FFs would see their input value change too soon and that would be bad as it would make all FFs transparent on the clock edge.

Then I simply took the FF and combinational devices and connected them to create 4-bit counter combinators.



By chaining four of these in series, via the carry bit, I created a 16-bit counter. I had to add a FF in-between 4-bit counter to buffer the signal and ensure the first FF in the next 4-bit counter would sample accurately - probably an issue with the way Reason handles CV internally in large networks. This does add extra clock cycles unfortunately, but there may be a cleaner way to buffer between these counters.

The BV512 vocoder display is used to display the 16-bit value - you can see the least-significant-bit on the far right, and the most-significant-bit on the far left. It takes some time to reach its maximum value before rolling back over to zero.



This was a very interesting little project and I was immensely satisfied to create a functioning 16-bit counter. Unfortunately other things came up and I lacked the time or energy to take this further, but I envisioned the following projects using these components:
  1. a simple finite state machine that can change CV values in response to events - essentially a way for things to change over time in a programmatic way. One example might be a CV signal that changes after a number of events have occurred.
  2. a multiplexer design that allows the selection of multiple incoming CV signals so that only one (or a set of several for multi-input muxes) passes through at a time. This would allow programmatic selection of various control signals in real-time.
  3. hundreds of other little ideas spinning around inside my head.

I also learned a valuable lesson - in future, when creating many, many different devices with different functions, keep a log! That way you know what these things all are when you look at them again six months later. Sigh.

One final note. It is known by some that if you have a NAND gate (negated-and), you can implement any combinational logic function with just NAND gates. I've provided a NOT and an AND gate; the NAND should be trivial. Good luck!


RNS files in this post:
You can pull the device patches directly from those files - I do not plan to publish individual patches separately.

One last comment - although my demonstrations use Thor buttons in a combi for visual feedback, this is for illustrative purposes only. It's important that the "digital" CV signals sit on the rails - i.e. -64 and +63, or whatever the equivalent scaling is. The Thor buttons in a combi are only on when the signal is at the top rail, but off for all other values. To properly debug any use of these devices, I recommend using the CV Monitor instead of "Thor buttons", and ensuring that the relevant Delay display is either "1" or "2000" and nothing in-between, otherwise these errors will propagate and eventually cause problems.

The examples in this article require Reason 4 or newer.