Wednesday, January 30, 2008

Programmable auto filter interface for C64 using Arduino

Demo video: http://www.youtube.com/watch?v=kKADOmFqRMs


Overview

A software / hardware combo that allows for control of the analog filter inside a Commodore 64 that is running Cynthcart from a host computer (eg, Macbok, PC).


Software
• 16-step filter sequencer
• Set the speed of the filter sequence (with intervals between values reaching 2ms)
• Set the length of the sequence from 1 to 16 beats
• Offset value allows for shifting the filter values up or down on a larger scale
• MIDI mode allows sending data directly to control the filter (this mode disables the sequencer)

Download the Max/MSP patch here:
http://milkcrate.com.au/_other/downloads/max_patches/C64_FILTER.zip

It requires Max/MSP runtime which can be downloaded from http://www.cycling74.com/.


Screenshot

Interface
The hardware is very simple, and is based around an Arduino board that is using a bit-banging SPI technique to write data to a 100KΩ digital pot (model MCP42100). Approximately 7 of the 8 bits of data actually change the value of the filter (this could be due to the resistance value of the pot).

Any microcontroller that can either do SPI natively or through bit-banging should be able to handle this simple operation.




Schematic
Notes:
• J1 1 to 14 refers to Arduino digital pins 0 to 13
• The datasheet for the MCP42100 recommends a 0.1uF or similar capacitor to smooth out the power supply. However, this has not been an issue.


Arduino Code

/* INITIALISATION */

int SS1 = 2; // set slave select 1 pin


int CLK = 3; // set clock pin


int MOUT = 4; // set master out, slave in pin


byte cmd_byte0 = B00010001; // command byte to write to pot 0, from the MCP42XXX datasheet


byte cmd_byte1 = B00010010; // command byte to write to pot 1, from the MCP42XXX datasheet


byte cmd_byte2 = B00010011; // command byte to write to pots 0 and 1, from the MCP42XXX datasheet


byte work; // setup a working byte, used to bit shift the data out


byte data;


/* SETUP */


void setup() { // setup function begins here

Serial.begin(57600);


pinMode(SS1, OUTPUT); // set CS pin to output


pinMode(CLK, OUTPUT); // set SCK pin to output


pinMode(MOUT, OUTPUT); // set MOSI pin to output


digitalWrite(SS1, HIGH); // hold slave select 1 pin high, so that chip is not selected to begin with


}


void spi_transfer(byte working) {


; // function to actually bit shift the data byte out


for(int i = 1; i <= 8; i++) { // setup a loop of 8 iterations, one for each bit


if (working > 127) { // test the most significant bit


digitalWrite (MOUT,HIGH); // if it is a 1 (ie. B1XXXXXXX), set the master out pin high


}


else {


digitalWrite (MOUT, LOW); // if it is not 1 (ie. B0XXXXXXX), set the master out pin low


}


digitalWrite (CLK,HIGH); // set clock high, the pot IC will read the bit into its register


working = working << 1;


digitalWrite(CLK,LOW); // set clock low, the pot IC will stop reading and prepare for the next iteration (next significant bit


}


}


void spi_out(int SS, byte cmd_byte, byte data_byte) { // SPI tranfer out function begins here


digitalWrite (SS, LOW); // set slave select low for a certain chip, defined in the argument in the main loop. selects the chip


work = cmd_byte; // let the work byte equal the cmd_byte, defined in the argument in the main loop


spi_transfer(work); // transfer the work byte, which is equal to the cmd_byte, out using spi


work = data_byte; // let the work byte equal the data for the pot


spi_transfer(work); // transfer the work byte, which is equal to the data for the pot


digitalWrite(SS, HIGH); // set slave select high for a certain chip, defined in the argument in the main loop. deselcts the chip


}


void loop () {


if(Serial.available() > 0) {


data = Serial.read();


spi_out(SS1, cmd_byte0, data); // send out data to chip 1, pot 0


delay(2); // set a short delay

}


}


Tuesday, January 29, 2008

Digital Overlay for Synthcart and MIDI2600


I made a little Max/MSP patch that shows an overlay for a pair of Atari 2600 CX-50 or similar keypads when used with Synthcart. This is handy for when one is not near a TV and/or the SynthCart manual. The patch sends a note on or off when each key is toggled by clicking on it. Alternatively, the patch will accept MIDI data. A Highly Liquid MIDI2600 module interfaces between the MIDI output and the Atari console.

Basically, it's good news if one wants to set up a certain sound easily without having to refer to a manual or a MIDI implementation chart. Download the patch here:
http://milkcrate.com.au/_other/downloads/max_patches/MIDI2600.gui.zip

The patch requires Max/MSP runtime, which can be acquired from Cycling74.

Demo video: http://www.youtube.com/watch?v=u6ljEBMKYJs

At last: Nanoloop 1.0 CD

Finally, i have managed to acquire a Nanoloop 1.0 CD. Highlights include tracks by Merzbow, Felix Kubin and the two by Oliver Wittchow himself.





Patch anatomy: looping

This is a tutorial on making a simple audio loop in Max/MSP.

The accompanying patches can be found here:
http://milkcrate.com.au/_other/downloads/max_patches/easy_loop/easy_loop_1.pat
http://milkcrate.com.au/_other/downloads/max_patches/easy_loop/easy_loop_2.pat

Let us begin!


Simple Patch
Let us begin with almost the simplest patch that will allow one to loop a piece of audio. This patch can then be expanded upon.


This simple patch allows the user to control four aspects of the loop:
• which file is being looped
• what the ratio of playback should be (this changes the speed and pitch accordingly)
• where the loop begins in relation to the audio in the file
• how long the loop is

The patch revolves around the groove~ object. The groove~ object controls the playback of a sample through its inlets and outlets. The groove~ object is associated with a buffer~ object by sharing the same name in their first argument. The groove~ object has the word "loop" as its first argument. The buffer~ object also has the word "loop" as its first argument. The word "loop" in this context acts as a name that binds the groove~ object to the buffer~ object.

The buffer~ is an allocated space in memory in which the sample that is played back via the groove~ is stored. The number after the name of the buffer~ (in this case the word "loop") is how long the sound file that is loaded into the buffer~ (and played back by the groove~) can be. This sets the maximum length of the file in ms.

In this patch, the maximum length of the buffer~ is 60000 ms or or one minute exactly. For example, if a wave file is loaded into the buffer~ that is two minutes long, only the first 60000 ms will be available to the groove~ object to play back. However, if a wave file is loaded into the buffer~ that is only forty seconds long, the entire 40 seconds will playback (even though 60 seconds was set as the seconds argument for the buffer~). In order to read a file into the buffer~ so that it can be played back by the groove~ object, the message "read" must be sent to the buffer~'s only inlet.

The groove~ object has three inlets and two outlets. The left-most inlet is used for control-type messages as well as changing the ratio of the sample that is being played. The middle inlet sets the start point of the loop in ms (where 0 is the beginning of the buffer~). The right inlet sets the end point of the loop in ms (where 0 is the beginning of the buffer~) .

Because the groove~ object does not loop by default, the message "loop 1, loopinterp 1" is sent upon opening the patch. This is done by first connecting a loadbang object to the message "loop 1, loopinterp 1" to the left inlet of the groove~ object. "loop 1" tells the groove~ object that it must loop. "interp 1" tells the groove~ object that it must interpolate samples when it repeated the looping section of the audio buffer~.

The three number boxes at the top of the patch control the three remaining parameters. The first box on the left controls the playback ratio of the groove~ object. The middle number box controls the loop starting point in ms. The right number box controls the loop length in ms.

The playback ratio control is connected to the left inlet of the groove~ object via a sig~object. The sig~ object transforms a number (such as what comes out of the number box) to a Max/MSP audio signal (which is what is used to control the ratio). However, we do not hear this audio signal directly - it is used to continuously change the playback ratio of the sample as the number box is changed. A ratio of 1.0 will play the looping sample at its original speed and pitch. A ratio of 0.5 will play the looping sample at half its original speed and an octave lower. A ratio of 2.0 will play the looping sample at twice its original speed and an octave higher. A negative ratio will play the sample in reverse.

Finally, it is a matter of setting the loop start and end times. The start time is simply a number box connected directly to the middle inlet of the groove~ object. The end time is a little more complex. The aim is to set the loop length in ms. However, the right inlet of the groove~ object sets the end point of the loop, not the loop length. In other words, we are dealing with a absolute value (in reference to the buffer~ length in milliseconds) instead of a delta value in comparison to our loop starting point.

The easiest way to work around this problem is to take the loop starting point and simply add a value (in ms) to it and then send the result to the right inlet of the groove~ object. This is why the loop start number box and the loop length number box go to the left and right inlets of a + object. This object performs the addition of both of these numbers.

The nature of the + means that a bang trigger is needed. This is because any changes in value to the left inlet will trigger the calculation, but the changes in the right inlet will not trigger the calculation directly. As a result, changes to the loop start point will update the groove~ start and finish loop points (because the loop start point is connected to the left inlet of the +). However, changes in the loop length will only be updated when the loop starting point has been changed.

The bang re-triggers the addition calculation every time the loop length changes by triggering the left inlet of the + object. Note the right-to-left order; the number from the loop length number box is sent to the right inlet of the + before the calculation is re-triggered. If the bang was to the right of the right inlet of the +, then the calculation would be triggered before the new value for the loop length had been sent.

Please note that in order to hear anything, the DSP Engine must be set to on (in Options > DSP Status > Audio).


Adding LFO Modulation
This simple extension adds the following features to the patch described above.
• LFO Sinewave modulation of the start point of the loop, resulting in a more complex sound and a wider variety of sounds.
• Control over modulation depth (in ms) and speed (in Hz).

The other features are retained.

The patch itself has not changed that much. The main structure from the first version is still almost completely intact. The only change in the original structure of the patch is that a + object has been added in between the loop start point number box and the rest of the patch. The loop start point number box is connected to the right inlet of the new + object.

Connected to the new + object is a sinewave generator (the cycle~ object) whose signal is routed through a signal monitor (which looks similar to a number box) and a scale object. The cycle~ object generates an audio waveform in shape of a sinewave. The frequency of this sinewave in Hz is determined by the number that is sent to its left inlet, which is connected to the mod speed number box.

The output of the sinewave is connected to the signal monitor, which is able to convert a signal into a number which is output to its left outlet. In the case of the sinewave, the numbers are in between -1.0 and 1.0. This stream of numbers is used as a starting point with which to modulation the loop start and end points with.

The numbers from the signal monitor object are sent to the scale object. The scale object takes four main arguments - low input, high input, low output and high output. The object takes a number and scales it as described by the four arguments. For example, if the scale object's four arguments are 0.0 1.0 0.0 10.0 and the value 0.5 was sent to the left inlet, then the scale object would return 5.0, because this value is to 0.0 and 10.0 what 0.5 is to 0.0 and 1.0.

Because we know that our source signal is a sinewave oscillator, we also know that the minimum data range that is generated by the sinewave is -1.0 and the maximum is 1.0. Hence, the first two arguments (the low input and the high input). The high output value is set by the mod depth number box as it is connected to the second-most-right inlet of the scale object.

This stream of numbers, as determined by the speed of the sinewave and the high output value of the scale object is then simply added to the user-determined starting point. This is how the modulation signal is integrated into the original structure of the patch.

Sunday, January 27, 2008

32 LED fader with Arduino

Although it may not seem like it at first, this post is a follow up to my previous post.

The Arduino only has a maximum of 14 digital outputs (if serial communication is not used) or 12 (if serial communication is used). It is quite easy to extend the number of digital outputs using a 74hc595 serial to parallel shift register.

But the problem with using the 74hc595s is that firstly, the serial data must be clocked out one bit at a time and that in order to change only one of the registers, all of the registers must be written to (because they are all chained together). So there is a limitation in terms of speed and efficiency.

The 74hc374 IC can be used to perform the same function but in a different way. By clocking out data in parallel to all the 74hc374 IC data input lines and then pulsing the clock input of only one of them, it is possible to selectively write to only one of the sets of outputs.

The process is very quick - keep in mind that in order to change the output state of one the ICs, a PORTD or PORTB message can be used to quickly set the entire byte in parallel. Then, the clock input pin of the IC in question simply needs to set high for five microseconds (not milliseconds!) and then low for the same amount of time.

In this context, it is just like using a chip select line and writing to that chip.

This idea can be extended to execute pulse width modulation on, say, thirty-two outputs across four 74hc374 ICs. In the example below, the PWM has a bit depth of eight (as far as the duty cycle is concerned).

Example Video
http://www.youtube.com/watch?v=ioDDVLI9cpQ


Schematic
Notes about the schematic:
• R1 to R32 should be calculated based on your power supply voltage and the rating of the LEDs you're using.
• PORTD refers to Arduino digital pins 0 to 7.
• PORTB refers to Arduino digital pins 8 to 13.


Breadboard
Code
/*

3 LED Fader using Flip-Flops

by Sebastian Tomczak

27 January 2007

*/


int strobe_time = 5;


void setup() {

DDRD = B11111111;

DDRB = B00111111 | DDRB;

PORTB = B00000000;

}


void write374(byte clkPin, byte data) {

PORTD = data;

digitalWrite(clkPin, HIGH);

delayMicroseconds(strobe_time);

digitalWrite(clkPin, LOW);

delayMicroseconds(strobe_time);

}


void loop() {

for(int loop1 = 0; loop1 < 4; loop1++) {

randomSeed(analogRead(0));

int a = random(255);

randomSeed(analogRead(1));

int b = random(255);

randomSeed(analogRead(2));

int c = random(255);

randomSeed(analogRead(3));

int d = random(255);

for(int k = 0; k < 256; k++) {

for(int i = 0; i < 3; i ++) {

delayMicroseconds(k * 10);

write374(8, a);

write374(9, b);

write374(10, c);

write374(11, d);

delayMicroseconds(2551 - (k * 10) + 1);

write374(8, 0);

write374(9, 0);

write374(10, 0);

write374(11, 0);

}

}

}

for(int j = 0; j < 256; j++) {

int a = 255 | j;

int b = j;

int c = 255 & j;

int d = 255 - j;

for(int k = 256; k > 0; k--) {

for(int i = 0; i < 3; i ++) {

delayMicroseconds(k * 10);

write374(8, a);

write374(9, 0);

write374(10, c);

write374(11, 0);

delayMicroseconds(2551 - (k * 10));

write374(8, 0);

write374(9, b);

write374(10, 0);

write374(11, d);

}

}

}

}

Saturday, January 26, 2008

Soft MIDI Pokey

The Pokey IC: Overview
The Pokey chip is a forty pin IC whose main functions include read keys and analog sensors, outputting serial data and generating audio. The audio section of the chip includes four oscillators which can operate in a number of modes which make it quite versatile (and it sounds great!)

Information on how to control the Pokey chip (ie. registers and functions) comes from a document by Bryan Edewaard. This project would obviously not be possible without fantastic work such as this!

The way that data is read or written to the chip is by the control of four address lines (A0 to A3, that control the register being written to or read from) and eight data lines (D0 to D7, that control the information that is sent to or retrieved from the chip).

Since we are interested in sound generation, let's focus on the relevant registers.

Registers 00 to 08 are responsible for all sounds that this chip can produce.

Registers 00 (0000), 02 (0010), 04 (0100) and 06 (0110) control the frequency of the four voices. The value is between 0 and 255 (00000000 and 11111111 in binary, where each bit represents one of the eight data lines).

Registers 01 (0001), 03 (0011), 05 (0101) and 07 (0111) control the timbral and volume aspects of each voice. The three most significant bits (xxx00000) control the timbre (whether the tone is a 'pure' square wave-type sound or has distortion of some sort).Bit four (000x0000) is used in digital to analog conversion, and should not be set to high for audio generation normally. Bits 0 to 3 (0000xxxx) set the volume of that voice.

Register 08 (1000) sets 'global' parameters that effect the way in which audio is generated. Here is the overview of each bit:

• Bit 7: Changes the type of noise
• Bit 6: Use the undivided clock to time voice 1
• Bit 5: Use the undivided clock to time voice 3
• Bit 4: Combine the frequency registers for voices 1 and 2, creating a single 16-bit oscillator
• Bit 3: Combine the frequency registers for voices 3 and 4, creating a single 16-bit oscillator
• Bit 2: Voice 1 is in high pass mode, set frequency with voice 2
• Bit 1: Voice 3 is in high pass mode, set frequency with voice 4
• Bit 0: Use a divide-by-120 clock or a divide-by-28 clock

So, in order to write data to the Pokey, at least 12 separate digital output lines are required in a circuit.


Updated Circuit and Code
I have been improving the method of controlling the Pokey chip. The improvements i have made are based almost completely on a schematic by Michael Hill. Without people like him, such projects would not be possible also!

I have adapted the schematic to suite the Arduino board. The code has also been re-written to accommodate for the extra chips. The Max/MSP patch now incorporates real-time MIDI controller (hence the title of this post -- the MIDI control is done in the host computer software, not embedded hardware).

The new circuit (thanks to Michael Hill for posting his design) employs two octal flip flops. In my case, i have used a pair of 74hc374 because this IC was readily available. The chip is named "octal edge triggered d-type flip flops with three state outputs". Basically, it consists of eight separate flip flop functions. A flip flop is an electronic device or circuit that changes its binary (ie. either high or low) output (Q) to match the state of the input (D) only when it is triggered by a clock signal (C). We can say that a flip flop stores a single bit of memory, because unless the flip flop is actually triggered, the output will remain the same regardless of the input. When the flip flop is triggered, the output will be updated to reflect the input.

The 374 IC is "edge triggered". Thus, the output (Q) is only updated to match the input state (D) when the clock signal (C) makes a transition from low to high. It follows that if the clock signal is either high or low, but not moving from a low to a high state, the output (Q) will not change (and will stay the same as when the output was last triggered). It should be noted that ll eight flip flops on the 374 share the same clock signal (that is, they all update at the same time).

The circuit makes use of this function by first clocking out the four bits required to set an address for a register of the Pokey to one of the 74hc374s and then clocking out the eight bits of data to the second 74hc374. The two 74hc374 have separate clocks. Then, the Pokey's chip select line is enabled and thus the data is written to the Pokey.

The basic principle of writing data to the chip is as follows:
• For each change, two bytes are sent from the host computer to the Arduino at a baud rate of 57600.
• The first byte that is sent is a number between 0 and 8, signifying the register to write data to.
• The second byte that sent is a number between 0 and 255, signifying the data to write into the previously selected register.
• First, the eight data lines are set the register byte. Then, the '374 that is connected to the register lines is pulsed so that the outputs of the IC set the correct register at the Pokey. However, because the other '374 is not strobed, the data lines are left unchanged.
• Next, the eight data lines are set to the data byte.
• The twelve LED's show the current register and data bytes. Then, the '374 that is connected to the data lines is pulsed so that the outputs of the IC set the correct data value at the Pokey.
• Finally, the chip select line actually writes allows the Pokey to read the data that has been sent to it.


MIDI Mapping
The Pokey chip is controlled by MIDI via a Max/MSP patch in the following way:
• Pitch is scaled from 0 to 127 to 0 to 255 and is mapped to frequency for channels 1 to 4
• MIDI CC#2 is scaled from 0 to 127 to 0 to 15 and is mapped to volume for channels 1 to 4
• MIDI CC#1 is scaled from 0 to 127 to 0 7 and is mapped to tone for channels 1 to 4
• MIDI CC#27 is scaled from 0 to 127 to a toggled state (on or off) for distortion type
• MIDI CC#26 is scaled from 0 to 127 to a toggled state (on or off) for undiv. clock voice 1
• MIDI CC#25 is scaled from 0 to 127 to a toggled state (on or off) for undiv. clock voice 3
• MIDI CC#24 is scaled from 0 to 127 to a toggled state (on or off) for 16 bit mode voices 1 and 2
• MIDI CC#23 is scaled from 0 to 127 to a toggled state (on or off) for 16 bit mode voices 3 and 4
• MIDI CC#22 is scaled from 0 to 127 to a toggled state (on or off) for high pass mode voice 1
• MIDI CC#21 is scaled from 0 to 127 to a toggled state (on or off) for high pass mode voice 3
• MIDI CC#20 is scaled from 0 to 127 to a toggled state (on or off) for clock div. 120 or div. 28



Schematic


Breadboard



Code

/*

Soft MIDI Controlled Pokey Chip

by Sebastian Tomczak

26 January 2007


*/


// Pokey Pins

int pokeyCS0 = 12; // chip select


// 74HC374 Pins

int addressClock = 10;

int dataClock = 11;

// d0 to d7 are on pins 2 - 9

// a0 to a3 are on pins 2 - 5


int strobe_wait = 100;


byte registerP;

byte dataP;


void writePortByte(byte PortByte) {

PORTD = PortByte << 2;

PORTB = PortByte >> 6 | B00010000; // OR pin 12 high because of CS0 inverse logic

}


void setup() {

Serial.begin(57600);

DDRD = DDRD | B11111110;

DDRB = DDRB | B00111111;

digitalWrite(pokeyCS0, HIGH); // CS0 has inverse logic (active low)

digitalWrite(addressClock, LOW);

digitalWrite(dataClock, LOW);

}


void loop() {

if(Serial.available() > 1) {

registerP = Serial.read();

dataP = Serial.read();



writePortByte(registerP);

digitalWrite(addressClock, HIGH);

delayMicroseconds(strobe_wait);



writePortByte(dataP);

digitalWrite(dataClock, HIGH);

delayMicroseconds(strobe_wait);



digitalWrite(pokeyCS0, LOW);

delayMicroseconds(strobe_wait);



digitalWrite(pokeyCS0, HIGH);

digitalWrite(dataClock, LOW);

digitalWrite(addressClock, LOW);

}

}

Thursday, January 24, 2008

Pokey: nested 'for' statements


An Atari Pokey sound chip is controlled directly via bus and data lines from an Arduino using three nested 'FOR' statements.

The results are much more complex (and musically interesting) than the code would lead one to believe - a minimalist / maximalist approach.

URL: http://youtube.com/watch?v=aRCPOhP-V7M

Wednesday, January 23, 2008

Exploratory composite video noise synthesis



By piggy backing a two-bit DAC signal of the correct voltage on a completely black composite video signal, a simple exploratory composite video noise synthesiser can be constructed. Each of the images below is of a relatively stable state that can be found by turning the two pots.

Sunday, January 20, 2008

Molecular Code live @ elektro gönner


Chris and i just finished playing at Elektro Gönner in Austria. You can hear one of the tracks here, with a nice little intro by Chris:

http://milkcrate.com.au/_other/downloads/mp3s/Luminometer.mp3

There is something surreal about getting up at 6.30am to play at a show in a night club on the other side of the world.

Some photos from the event, then:


Saturday, January 19, 2008

Adventures with Pokey



I am managing to control the sounds of the Pokey chip a little bit more. The main problem that i was having initially was that the fact that the chips seems to reset the channel registers when the master audio control register had been updated. This took some time to track down (it didn't seem like obvious behaviour to me).

So. The first example is the Pokey being controlled through the Arduino using Max/MSP in a sequencer-like fashion.

Download the riff: http://milkcrate.com.au/_other/downloads/mp3s/pokey_sequenced.mp3


I am very happy with these initial results, and feel that this chip warrants further creative exploration.

Demo video: http://www.youtube.com/watch?v=Gc3HexrFpsQ


"Controlling an Atari Pokey chip with an Arduino board using Max/MSP. This is an initial test of a pair of oscillators in one of the combined modes.

The master clock is generated by a 74HC14, so it is a variable clock making for a larger range of frequencies. "



Schematic:

With the audio examples above i didn't use use the data line D-0 (least significant bit). In the schematic, Arduino pin 12 (labeled 13 on the diagram) is connected to D0. The reason is that in the Arduino code, i simply set PORTD (Arduino pins 7 to 0) to the incoming serial data byte, and connected Pokey lines D7 - D1 to Arduino pins 7 to 1.

However, since Arduino pin 0 is used as the host computer to Arduino serial RX pin, the lowest bit / pin of the Pokey is not set. Th data itself coming from the computer was from 0 - 127 and then simply left-shifted by one bit place (to give the even numbers from 0 to 255, thereby ignoring pin 0 of the Arduino / Pokey setup).

Friday, January 18, 2008

Poking the pokey


A pokey on a breadboard.

Wednesday, January 16, 2008

Talking to 3 595's via Max/MSP

This is a follow up to a previous post regarding the connection of three 595 registers to an Arduino board and is a response to a question someone has asked me. What i did not cover in that post is how to actually make the connection between a host computer and the shift registers.

Let us review quickly how the Arduino sketch passes on the data to the 595 registers. Basically, the Arduino waits until its serial buffer has received three bytes. Then, each of these bytes is read and shifted out into the registers. The first byte will go to the 595 IC that is furthest away from the Arduino in the serial input / Q7' output chain (see the previous post for the hardware setup). The baud rate is 57600.

The 8 bits from each byte represents each of the outputs of the 595 register, like so:

bit 7 = 595 output Q7 (pin 7)
bit 6 = 595 output Q6 (pin 6)
bit 5 = 595 output Q5
(pin 5)
bit 4 = 595 output Q4
(pin 4)
bit 3 = 595 output Q3
(pin 3)
bit 2 = 595 output Q2
(pin 2)
bit 1 = 595 output Q1
(pin 1)
bit 0 = 595 output Q0
(pin 15)


So, it is possible to use an 8 bit value (from 0 to 255) to independently represent the 8 digital output pins Q0 to Q7 on the 595. It follows that we can control the three 595 shift registers quite easily from Max/MSP with a patch such as this one:


The main patch.



The sto.8b1b encapsulation that is referenced in the main patch.

How does this patch work? Well, twenty-four toggles each represents a bit in three bytes of information. Whenever the value of a toggle is changed, then the entire updated byte of information is sent out of the bottom of the sto.8b1b encapsulation as an integer (0 to 255).

These three bytes need to be sent for every change that occurs within the three bytes because the Arduino is expecting to see three bytes of serial data in order to set the three shift registers. Furthermore, these three bytes must be sent in a particular order - the third shift register must be sent first, the first shift register must be sent last.

In order to get the proper sequence of bytes, the three values are grouped together in a list via the pack object. The list in then unpacked, and because of Max's right-to-left order, the third item in the list is sent to the serial object first and so on.

The serial object is connected to the Arduino at a baud rate of 57600.

It is evident that this may be an inefficient means of updating the three shift registers, because three bytes must be sent in order to change a single bit of information output. This may suffice in many situations. But it is possible to use a numbering prefix (1 to 3) to control the register. This would require a reworking of the Arduino code.

Download this patch here: http://milkcrate.com.au/_other/downloads/max_patches/Three_595s/.