Playing with Max 6 Framework

Exclusive offer: get 50% off this eBook here
C Programming for Arduino

C Programming for Arduino — Save 50%

Learn how to program and use Arduino boards with a series of engaging examples, illustrating each core concept with this book and ebook

$29.99    $15.00
by Julien Bayle | September 2013 | Open Source

This article by Julien Bayle, the author of C programming for Arduino, teaches some tips and techniques we can use with the Max 6 graphical programming framework. We will completely describe the use of the Serial object and how to parse and select data coming from Arduino to the computer. We will design a small sound-level meter using both real LEDs and Max 6 and finish by designing a Pitch shift sound effect controlled by our own hand and a distance sensor.

In this article, we will learn how to send data to Arduino from Max 6. We will also describe how we can handle and parse the data being received from Arduino. Arduino adds a lot of features to your Max 6 programs. Indeed, it provides a way to plug Max 6 into the real physical world. Through two examples, we are going to understand a nice way of working with Arduino, the computer and most advanced programming framework ever.

(For more resources related to this topic, see here.)

Communicating easily with Max 6 – the [serial] object

The easiest way to exchange data between your computer running a Max 6 patch and your Arduino board is via the serial port. The USB connector of our Arduino boards includes the FTDI integrated circuit EEPROM FT-232 that converts the RS-232 plain old serial standard to USB.

We are going to use again our basic USB connection between Arduino and our computer in order to exchange data here.

The [serial] object

We have to remember the [serial] object's features. It provides a way to send and receive data from a serial port. To do this, there is a basic patch including basic blocks. We are going to improve it progressively all along this article.

The [serial] object is like a buffer we have to poll as much as we need. If messages are sent from Arduino to the serial port of the computer, we have to ask the [serial] object to pop them out. We are going to do this in the following pages.

This article is also a pretext for me to give you some of my tips and tricks in Max 6 itself. Take them and use them; they will make your patching life easier.

Selecting the right serial port

we have used the message (print) sent to [serial] in order to list all the serial ports available on the computer. Then we checked the Max window. That was not the smartest solution. Here, we are going to design a better one.

We have to remember the [loadbang] object. It fires a bang, that is, a (print) message to the following object as soon as the patch is loaded. It is useful to set things up and initialize some values as we could inside our setup() block in our Arduino board's firmware.

Here, we do that in order to fill the serial port selector menu. When the [serial] object receives the (print) message, it pops out a list of all the serial ports available on the computer from its right outlet prepended by the word port. We then process the result by using [route port] that only parses lists prepended with the word port.

The [t] object is an abbreviation of [trigger]. This object sends the incoming message to many locations, as is written in the documentation, if you assume the use of the following arguments:

  • b means bang
  • f means float number
  • i means integer
  • s means symbol
  • l means list (that is, at least one element)

We can also use constants as arguments and as soon as the input is received, the constant will be sent as it is.

At last, the [trigger] output messages in a particular order: from the rightmost outlet to the leftmost one.

So here we take the list of serial ports being received from the [route] object; we send the clear message to the [umenu] object (the list menu on the left side) in order to clear the whole list. Then the list of serial ports is sent as a list (because of the first argument) to [iter]. [iter] splits a list into its individual elements.

[prepend] adds a message in front of the incoming input message.

That means the global process sends messages to the [umenu] object similar to the following:

  • append xxxxxx
  • append yyyyyy

Here xxxxxx and yyyyyy are the serial ports that are available.

This creates the serial port selector menu by filling the list with the names of the serial ports. This is one of the typical ways to create some helpers, in this case the menu, in our patches using UI elements.

As soon as you load this patch, the menu is filled, and you only have to choose the right serial port you want to use. As soon as you select one element in the menu, the number of the element in the list is fired to its leftmost outlet. We prepend this number by port and send that to [serial], setting it up to the right-hand serial port.

Polling system

One of the most used objects in Max 6 to send regular bangs in order to trigger things or count time is [metro].

We have to use one argument at least; this is the time between two bangs in milliseconds.

Banging the [serial] object makes it pop out the values contained in its buffer.

If we want to send data continuously from Arduino and process them with Max 6, activating the [metro] object is required. We then send a regular bang and can have an update of all the inputs read by Arduino inside our Max 6 patch.

Choosing a value between 15 ms and 150 ms is good but depends on your own needs.

Let's now see how we can read, parse, and select useful data being received from Arduino.

Parsing and selecting data coming from Arduino

First, I want to introduce you to a helper firmware inspired by the Arduino2Max page on the Arduino website but updated and optimized a bit by me. It provides a way to read all the inputs on your Arduino, to pack all the data read, and to send them to our Max 6 patch through the [serial] object.

The readAll firmware

The following code is the firmware.

int val = 0; void setup() { Serial.begin(9600); pinMode(13,INPUT); } void loop() { // Check serial buffer for characters incoming if (Serial.available() > 0){ // If an 'r' is received then read all the pins if (Serial.read() == 'r') { // Read and send analog pins 0-5 values for (int pin= 0; pin<=5; pin++){ val = analogRead(pin); sendValue (val); } // Read and send digital pins 2-13 values for (int pin= 2; pin<=13; pin++){ val = digitalRead(pin); sendValue (val); } Serial.println();// Carriage return to mark end of data flow. delay (5); // prevent buffer overload } } } void sendValue (int val){ Serial.print(val); Serial.write(32); // add a space character after each value sent }

For starters, we begin the serial communication at 9600 bauds in the setup() block.

As usual with serial communication handling, we check if there is something in the serial buffer of Arduino at first by using the Serial.available() function. If something is available, we check if it is the character r. Of course, we can use any other character. r here stands for read, which is basic. If an r is received, it triggers the read of both analog and digital ports. Each value (the val variable) is passed to the sendValue()function; this basically prints the value into the serial port and adds a space character in order to format things a bit to provide an easier parsing by Max 6. We could easily adapt this code to only read some inputs and not all. We could also remove the sendValue() function and find another way of packing data.

At the end, we push a carriage return to the serial port by using Serial.println(). This creates a separator between each pack of data that is sent.

Now, let's improve our Max 6 patch to handle this pack of data being received from Arduino.

The ReadAll Max 6 patch

The following screenshot is the ReadAll Max patch that provides a way to communicate with our Arduino:

Requesting data from Arduino

First, we will see a [t b b] object. It is also a trigger, ordering bangs provided by the [metro] object. Each bang received triggers another bang to another [trigger] object, then another one to the [serial] object itself.

The [t 13 r] object can seem tricky. It just triggers a character r and then the integer 13. The character r is sent to [spell] that converts it to ASCII code and then sends the result to [serial]. 13 is the ASCII code for a carriage return.

This structure provides a way to fire the character r to the [serial] object, which means to Arduino, each time that the metro bangs. As we already see in the firmware, it triggers Arduino to read all its inputs, then to pack the data, and then to send the pack to the serial port for the Max 6 patch.

To summarize what the metro triggers at each bang, we can write this sequence:

  1. Send the character r to Arduino.
  2. Send a carriage return to Arduino.
  3. Bang the [serial] object.

This triggers Arduino to send back all its data to the Max patch.

Parsing the received data

Under the [serial] object, we can see a new structure beginning with the [sel 10 13] object. This is an abbreviation for the [select] object. This object selects an incoming message and fires a bang to the specific output if the message equals the argument corresponding to the specific place of that output. Basically, here we select 10 or 13. The last output pops the incoming message out if that one doesn't equal any argument.

Here, we don't want to consider a new line feed (ASCII code 10). This is why we put it as an argument, but we don't do anything if that's the one that has been selected. It is a nice trick to avoid having this message trigger anything and even to not have it from the right output of [select].

Here, we send all the messages received from Arduino, except 10 or 13, to the [zl group 78] object. The latter is a powerful list for processing many features. The group argument makes it easy to group the messages received in a list. The last argument is to make sure we don't have too many elements in the list. As soon as [zl group] is triggered by a bang or the list length reaches the length argument value, it pops out the whole list from its left outlet.

Here, we "accumulate" all the messages received from Arduino, and as soon as a carriage return is sent (remember we are doing that in the last rows of the loop() block in the firmware), a bang is sent and all the data is passed to the next object.

We currently have a big list with all the data inside it, with each value being separated from the other by a space character (the famous ASCII code 32 we added in the last function of the firmware).

This list is passed to the [itoa] object. itoa stands for integer to ASCII . This object converts integers to ASCII characters.

The [fromsymbol] object converts a symbol to a list of messages.

Finally, after this [fromsymbol] object we have our big list of values separated by spaces and totally readable.

We then have to unpack the list. [unpack] is a very useful object that provides a way to cut a list of messages into individual messages. We can notice here that we implemented exactly the opposite process in the Arduino firmware while we packed each value into a big message.

[unpack] takes as many arguments as we want. It requires knowing about the exact number of elements in the list sent to it. Here we send 12 values from Arduino, so we put 12 i arguments. i stands for integer . If we send a float, [unpack] would cast it as an integer. It is important to know this. Too many students are stuck with troubleshooting this in particular.

We are only playing with the integer here. Indeed, the ADC of Arduino provides data from 0 to 1023 and the digital input provides 0 or 1 only.

We attached a number box to each output of the [unpack] object in order to display each value.

Then we used a [change] object. This latter is a nice object. When it receives a value, it passes it to its output only if it is different from the previous value received. It provides an effective way to avoid sending the same value each time when it isn't required.

Here, I chose the argument -1 because this is not a value sent by the Arduino firmware, and I'm sure that the first element sent will be parsed.

So we now have all our values available. We can use them for different jobs.

But I propose to use a smarter way, and this will also introduce a new concept.

Distributing received data and other tricks

Let's introduce here some other tricks to improve our patching style.

Cordless trick

We often have to use some data in our patches. The same data has to feed more than one object.

A good way to avoid messy patches with a lot of cord and wires everywhere is to use the [send] and [receive] objects. These objects can be abbreviated with [s] and [r], and they generate communication buses and provide a wireless way to communicate inside our patches.

These three structures are equivalent.

The first one is a basic cord. As soon as we send data from the upper number box, it is transmitted to the one at the other side of the cord.

The second one generates a data bus named busA. As soon as you send data into [send busA], each [receive busA] object in your patch will pop out that data.

The third example is the same as the second one, but it generates another bus named busB.

This is a good way to distribute data.

I often use this for my master clock, for instance. I have one and only one master clock banging a clock to [send masterClock], and wherever I need to have that clock, I use [receive masterClock] and it provides me with the data I need.

If you check the global patch, you can see that we distribute data to the structures at the bottom of the patch. But these structures could also be located elsewhere. Indeed, one of the strengths of any visual programming framework such as Max 6 is the fact that you can visually organize every part of your code exactly as you want in your patcher. And please, do that as much as you can. This will help you to support and maintain your patch all through your long development months.

Check the previous screenshot. I could have linked the [r A1] object at the top left corner to the [p process03] object directly. But maybe this will be more readable if I keep the process chains separate. I often work this way with Max 6.

This is one of the multiple tricks I teach in my Max 6 course. And of course, I introduced the [p] object, that is the [patcher] abbreviation.

Let's check a couple of tips before we continue with some good examples involving Max 6 and Arduino.

Encapsulation and subpatching

When you open Max 6 and go to File | New Patcher , it opens a blank patcher. The latter, if you recall, is the place where you put all the objects. There is another good feature named subpatching . With this feature, you can create new patchers inside patchers, and embed patchers inside patchers as well.

A patcher contained inside another one is also named a subpatcher.

Let's see how it works with the patch named ReadAllCutest.maxpat.

There are four new objects replacing the whole structures we designed before.

These objects are subpatchers. If you double-click on them in patch lock mode or if you push the command key (or Ctrl for Windows), double-click on them in patch edit mode and you'll open them. Let's see what is there inside them.

The [requester] subpatcher contains the same architecture that we designed before, but you can see the brown 1 and 2 objects and another blue 1 object. These are inlets and outlets. Indeed, they are required if you want your subpatcher to be able to communicate with the patcher that contains it. Of course, we could use the [send] and [receive] objects for this purpose too.

The position of these inlets and outlets in your subpatcher matters. Indeed, if you move the 1 object to the right of the 2 object, the numbers get swapped! And the different inlets in the upper patch get swapped too. You have to be careful about that. But again, you can organize them exactly as you want and need.

Check the next screenshot:

And now, check the root patcher containing this subpatcher. It automatically inverts the inlets, keeping things relevant.

Let's now have a look at the other subpatchers:

The [p portHandler] subpatcher

The [p dataHandler] subpatcher

The [p dataDispatcher] subpatcher

In the last figure, we can see only one inlet and no outlets. Indeed, we just encapsulated the global data dispatcher system inside the subpatcher. And this latter generates its data buses with [send] objects. This is an example where we don't need and even don't want to use outlets. Using outlets would be messy because we would have to link each element requesting this or that value from Arduino with a lot of cords.

In order to create a subpatcher, you only have to type n to create a new object, and type p, a space, and the name of your subpatcher.

While I designed these examples, I used something that works faster than creating a subpatcher, copying and pasting the structure on the inside, removing the structure from the outside, and adding inlets and outlets.

This feature is named encapsulate and is part of the Edit menu of Max 6.

You have to select the part of the patch you want to encapsulate inside a subpatcher, then click on Encapsulate , and voilà! You have just created a subpatcher including your structures that are connected to inlets and outlets in the correct order.

Encapsulate and de-encapsulate features

You can also de-encapsulate a subpatcher. It would follow the opposite process of removing the subpatcher and popping out the whole structure that was inside directly outside.

Subpatching helps to keep things well organized and readable.

We can imagine that we have to design a whole patch with a lot of wizardry and tricks inside it. This one is a processing unit, and as soon as we know what it does, after having finished it, we don't want to know how it does it but only use it .

This provides a nice abstraction level by keeping some processing units closed inside boxes and not messing the main patch.

You can copy and paste the subpatchers. This is a powerful way to quickly duplicate process units if you need to. But each subpatcher is totally independent of the others. This means that if you need to modify one because you want to update it, you'd have to do that individually in each subpatcher of your patch.

This can be really hard.

Let me introduce you to the last pure Max 6 concept now named abstractions before I go further with Arduino.

Abstractions and reusability

Any patch created and saved can be used as a new object in another patch. We can do this by creating a new object by typing n in a patcher; then we just have to type the name of our previously created and saved patch.

A patch used in this way is called an abstraction .

In order to call a patch as an abstraction in a patcher, the patch has to be in the Max 6 path in order to be found by it. You can check the path known by Max 6 by going to Options | File Preferences . Usually, if you put the main patch in a folder and the other patches you want to use as abstractions in that same folder, Max 6 finds them.

The concept of abstraction in Max 6 itself is very powerful because it provides reusability .

Indeed, imagine you need and have a lot of small (or big) patch structures that you are using every day, every time, and in almost every project. You can put them into a specific folder on your disk included in your Max 6 path and then you can call (we say instantiate ) them in every patch you are designing.

Since each patch using it has only a reference to the one patch that was instantiated itself, you just need to improve your abstraction; each time you load a patch using it, the patch will have up-to-date abstractions loaded inside it.

It is really easy to maintain all through the development months or years.

Of course, if you totally change the abstraction to fit with a dedicated project/patch, you'll have some problems using it with other patches. You have to be careful to maintain even short documentation of your abstractions.

Let's now continue by describing some good examples with Arduino.

C Programming for Arduino Learn how to program and use Arduino boards with a series of engaging examples, illustrating each core concept with this book and ebook
Published: May 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Creating a sound-level meter with LEDs

This small project is a typical example of a Max 6/Arduino hardware and software collaboration.

Max can easily listen for sounds and convert them from the analog to the digital domain.

We are going to build a small sound level visualizer using Arduino, some LEDs, and Max 6.

The circuit

The following figure shows the circuit:

Our double series of eight LEDs

Our double series of eight LEDs

The basic idea is to:

  • Use each series of eight LEDs for each sound channel (left and right)
  • Display the sound level all along the LED series

For each channel, the greater the number of LEDs switched on, the higher the sound level.

Let's now check how we can handle this in Max 6 first.

The Max 6 patch for calculating sound levels

Have a look at the following figure showing the SoundLevelMeters patch:

Generating sounds and measuring sound levels

We are using the MSP part of the Max 6 framework here that is related to sound signals. We have two sources (named source 1 and source 2) in the patch. Each one generates two signals. I connected each one to one of the [selector~ ] objects.

Those latter are switches for signals. The source selector at the top left provides a way to switch between source 1 and source 2.

I won't describe the cheap wizardry of sound sources; it would involve having a knowledge of synthesis and that would be out of the scope of this topic.

Then, we have a connection between each [selector~ ] output and a small symbol like a speaker. This is related to the sound output of your audio interface.

I also used the [meter~] object to display the level of each channel.

At last, I added a [flonum] object to display the current value of the level each time.

These are the numbers we are going to send to Arduino.

Let's add the serial communication building blocks we already described.

Sending data to Arduino

We have our serial communication setup ready.

We also have the [zmap 0. 1. 0 255] objects. These take a value intended to be between 0. 1, as was set up in the arguments, and scale it to the range 0 255. This provides a byte of data for each channel.

We are using two data buses to send a value from each channel to a [pak] object. The latter collects the incoming messages and creates a list with them. The difference between [pack] and [pak] is that [pak] sends data as soon as it receives a message in one of its inputs, not only when it receives a message of its left input, as with [pack].

Thus, we have lists of messages that are popped out from the computer to Arduino as soon as the level values change.

The firmware for reading bytes

Let's see how to handle this in Arduino:

#include <ShiftOutX.h> #include <ShiftPinNo.h> int CLOCK_595 = 4; // first 595 clock pin connecting to pin 4 int LATCH_595 = 3; // first 595 latch pin connecting to pin 3 int DATA_595 = 2; // first 595 serial data input pin connecting to pin 2 int SR_Number = 2; // number of shift registers in the chain // instantiate and enabling the shiftOutX library with our circuit
parameters shiftOutX regGroupOne(LATCH_595, DATA_595, CLOCK_595, MSBFIRST, SR_
Number); // random groove machine variables int counter = 0; byte LeftChannel = B00000000 ; // store left channel Leds infos byte RightChannel = B00000000 ; // store right channel Leds infos void setup() { // NO MORE setup for each digital pin of the Arduino // EVERYTHING is made by the library :-) } void loop(){ if (Serial.available() > 0) { LeftChannel = (byte)Serial.parseInt(); RightChannel = (byte)Serial.parseInt(); unsigned short int data; // declaring the data container as a very
local variable data = ( LeftChannel << 8 ) | RightChannel; // aggregating the 2
read bytes shiftOut_16(DATA_595, CLOCK_595, MSBFIRST, data); // pushing the
whole data to SRs // make a short pause before changing LEDs states delay(2); } }

We are doing that with Serial.parseInt() in the Serial.available() test.

This means that as soon as the data is in the Arduino serial buffer, we'll read it. Actually, we are reading two values and storing them, after a byte conversion, in LeftChannel and RightChannel.

We then process the data to the shift register to light the LEDs according to the value sent by the Max 6 patch.

Let's take another example of playing with sound files and a distance sensor.

Pitch shift effect controlled by hand

Pitch shifting is a well-known effect in all fields related to sound processing. It changes the pitch of an incoming sound. Here we are going to implement a very cheap pitch shifter with Max 6, but we will focus on how to control this sound effect. We will control it by moving our hand over a distance sensor.

The circuit with the sensor and the firmware

The following circuit shows the Arduino board connected to a sensor:

The Sharp distance sensor connected to Arduino

The firmware is almost the same too. I removed the part about the distance calculation because, indeed, we don't care about the distance itself.

The ADC of Arduino provides a resolution of 10 bits, which will give numbers from 0 to 1023. We are going to use this value to calibrate our system.

The following code is the firmware.

int sensorPin = 0; // pin number where the SHARP GP2Y0A02YK
is connected int sensorValue = 0 ; // storing the value measured from 0 to
1023 void setup() { Serial.begin(9600); } void loop(){ sensorValue = analogRead(sensorPin); // read/store the value from sensor Serial.println(sensorValue); delay(20); }

As soon as Arduino runs this firmware, it sends values to the serial port.

The patch for altering the sound and parsing Arduino messages

I cannot describe the whole pitch shifter itself. By the way, you can open the related subpatch to see how it has been designed. Everything is open.

The pitch shifter controlled by your hand over the distance sensor

As we described before, we have to choose the right serial port and then bang the [serial] object in order to make it pop out the values in its buffer.

Here, we are using the [scale] object. It is similar to [zmap], which we already used, because it maps a range to another one but it can also work with inverted range and doesn't clip values.

Here, I'm mapping values being received from the ADC of Arduino from 0 to 1023 to something fitting our need from 12.0 to 0.5.

If we place our hand close to the sensor, the distance is small, and if we move our hand further away, the distance changes and the effect is modulated.

Summary

This article taught us how to deal with Arduino using Max 6.

We learnt a bit more about some usual techniques in Max 6, and we practiced some concepts previously learnt in this article. Obviously, there is more to learn in Max 6, and I'd like to give you some good pointers for better learning.

Firstly, I'd suggest you read all the tutorials, beginning with those about Max, then about MSP, and then about digital sound, and at last about Jitter if you are interested in visuals and OpenGL. That sounds obvious but I still have two or three persons a day asking me where to begin Max 6 from. The answer is: tutorials.

Then, I'd suggest you design a small system. Less is definitely more. A small system provides easy ways to maintain, modify, and support. Using comments is also a nice way to quickly remember what you tried to do in this or that part.

Lastly, patching a bit everyday is the real key to success. It takes time, but don't we want to become masters?

Resources for Article :


Further resources on this subject:


C Programming for Arduino Learn how to program and use Arduino boards with a series of engaging examples, illustrating each core concept with this book and ebook
Published: May 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Julien Bayle

Julien Bayle owns his Master Degree of biology & computer sciences in 2000. After several years in pure IT System Design, he founded Design the Media early 2010 in order to provide his own courses, training & tools for art fields. As a digital artist, he designed some huge new media art installations, like the permanent exhibition of La Maison des Cinématographies de la Méditerranée (Château de la Buzine) in Marseille, France, in 2011. He also works as a new media technology consultant for some private & public entities. As an A/V live performer, he plays his cold electronic music from New York to Marseille, where he actually lives. Arduino framework is one of his first electronic hardware studies early 2005 and he designed the famous protodeck controller with some opensource framework too. As an art & technology teacher, also certified by Ableton in 2010, he teaches a lot of courses about the digital audio workstation named Ableton Live, about the real-time graphical programming framework Max6 and also about Processing and Arduino.

As a minimalist digital artist, he works at the crossroads of sound, visual and data. He explores relationships between sounds and visuals through his immersive A/V installations, his live performances and his released music. His work, often described as “complex, intrigating and relevant”, tries to break classical codes to bring audience a new vision of our world through his pure digital and real-time generated stimuli.

He's deeply involved in the open source community and loves to share and provide workshops and masterclasses online and on-site too. His personal website is http://julienbayle.net.

Books From Packt


Mac Application Development by Example: Beginner's Guide
Mac Application Development by Example: Beginner's Guide

Cinder Creative Coding Cookbook
Cinder Creative Coding Cookbook

Processing 2: Creative Programming Cookbook
Processing 2: Creative Programming Cookbook

Processing 2: Creative Coding Hotshot
Processing 2: Creative Coding Hotshot

Mastering openFrameworks: Creative Coding Demystified
Mastering openFrameworks: Creative Coding Demystified

Cinder – Begin Creative Coding
Cinder – Begin Creative Coding

Raspberry Pi Media Center
Raspberry Pi Media Center

Raspberry Pi Home Automation with Arduino
Raspberry Pi Home Automation with Arduino


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software