Max + Arduino play song while certain number

Dylan de Bruijn's icon

Hello everyone,

I'm busy with a project involving an Arduino and MaxMSP. I wired two potentiometers to my Arduino and uploaded code to it so I can read the analog values of these potentiometers in MaxMSP. My idea is simple. I want 6 audiochannels with different songs. All these channels play when the patch loads but are muted. When the potentiometer outputs 1 channel 1 unmutes. When the potentiometer outputs 2 channel 2 unmutes and everything else mutes again. I tried something with [select] and a [toggle] but select keeps banging the toggle and that's not what I want.

I hope someone would be so kind to help me. I can provide other information or a sketch of what I want if needed.

Thanks in advance.

Source Audio's icon

I would suggest to rather do the splitting of pot range in Arduino,
and send 6 numbers to Max only when numbers change.
That would significally reduce serial data flow.
But if You want to do that in max,
change object should be inserted to filter out repeated triggering.
See here one example :

Max Patch
Copy patch and select New From Clipboard in Max.

But all that could be done in Arduino :
int lastPot1 = 0;

void setup() {Serial.begin(9600);}

void loop() {int Pot1 = map(analogRead(A0), 0, 1023, 0, 6);
if(Pot1 != lastPot1) {Serial.println(Pot1);}
lastPot1 = Pot1; delay(50);}

That would send poti 0 - 6 only if value changed

Dylan de Bruijn's icon

Hello, thanks for your reply. I appreciate it very much. I added your code to my Arduino code, but the value in Max is still from 0 to 1023. And the toggle still keeps blinking.

Patch

Max Patch
Copy patch and select New From Clipboard in Max.

Arduino code

/* 
 ---- CMD SimpleMessageSystem ----
 Control Arduino board functions with the following messages:
 
 r a -> read analog pins
 r d -> read digital pins
 w d [pin] [value] -> write digital pin
 w a [pin] [value] -> write analog pin
 w s [pin] [value] -> write servo pin
 
 
 Base: Thomas Ouellet Fredericks 
 Additions: Alexandre Quessy, Thijs Eerens
 
 */

// Include de SimpleMessageSystem library
#include <SimpleMessageSystem.h> 
#include <Servo.h> 

Servo myservo;  // create servo object to control a servo  


// list the digital ports which are used as input
int digitalPorts[] = {2,3,4,5,6,7,8,9,10,11,12,13};

// list the analog ports which are used as input
int analogPorts[] = {0,1,2,3,4,5};

int lastPot1 = 0;

void setup()
{

  // The following command initiates the serial port at 9600 baud. Please note this is VERY SLOW!!!!!! 
  // I suggest you use higher speeds in your own code. You can go up to 115200 with the USB version, that's 12x faster
  Serial.begin(115200); //Baud set at 9600 for compatibility, CHANGE!

}

void loop()
{

  int Pot1 = map(analogRead(A1), 0, 1023, 0, 6);
  if(Pot1 != lastPot1) {Serial.println(Pot1);}
  lastPot1 = Pot1; delay(50);

  if (messageBuild() > 0) { // Checks to see if the message is complete and erases any previous messages
    switch (messageGetChar()) { // Gets the first word as a character
    case 'r': // Read pins (analog or digital)
      readpins(); // Call the readpins function
      break; // Break from the switch
    case 'w': // Write pin
      writepin(); // Call the writepin function
    }

  }

}

void readpins(){ // Read pins (analog or digital)

  int size;
  
  switch (messageGetChar()) { // Gets the next word as a character

    case 'd': // READ digital pins
    messageSendChar('d');  // Echo what is being read
    
    
    size = sizeof(digitalPorts) / sizeof(int); // get number of ports in digitalPorts list
    
    for (int thisPin = 0; thisPin < size; thisPin++) {
      messageSendInt(digitalRead(digitalPorts[thisPin])); // read each digital pin in the list
    }
    

      messageEnd(); // Terminate the message being sent
    break; // Break from the switch

    case 'a': // READ analog pins
    messageSendChar('a');  // Echo what is being read
    
    size = sizeof(analogPorts) / sizeof(int); // get number of ports in analogPorts list
    
    for (int thisPin = 0; thisPin < size; thisPin++) {
      messageSendInt(analogRead(analogPorts[thisPin])); // read each digital pin in the list
    }


      messageEnd(); // Terminate the message being sent
  }

}

void writepin() { // Write pin

    int pin;
  int state;

  switch (messageGetChar()) { // Gets the next word as a character

    case 'a' : // WRITE an analog pin

    pin = messageGetInt(); // Gets the next word as an integer
    state = messageGetInt(); // Gets the next word as an integer
    pinMode(pin, OUTPUT); //Sets the state of the pin to an output
    analogWrite(pin, state); //Sets the PWM of the pin 
    break;  // Break from the switch


    // WRITE a digital pin
  case 'd' : 

    pin = messageGetInt();  // Gets the next word as an integer
    state = messageGetInt();  // Gets the next word as an integer
    pinMode(pin,OUTPUT);  //Sets the state of the pin to an output
    digitalWrite(pin,state);  //Sets the state of the pin HIGH (1) or LOW (0)


      // WRITE a servo pin 
  case 's' : 

    pin = messageGetInt();  // Gets the next word as an integer
    state = messageGetInt();  // Gets the next word as an integer
    myservo.attach(pin);  // attaches the servo on pin to the servo object 
    myservo.write(state);  // sets the servo position according to the scaled value 

  }

}

Context

I have an old Philips radio which I emptied of all contents. So It's just an empty shell right now. But I want to put an Arduino in with a potentiometer for volume and a rotary switch (12 channels) for changing the radio channels. The potentiometer and rotaryswitch should send their values to MaxMSP. I haven't got the rotary switch working so I use two potentiometers for now.

Idea

My idea is that there are 12 audiochannels in Max that play MP3, WAV or any other easy to use soundformat. These channels are all linked to the first potentiometer (volumecontrol). All the channels are playing in the background but muted when the patch starts. When the potentiometer (rotary switch) outputs value 1 > channel 1 unmutes. When the potentiometer (rotary switch) outputs value 2 > channel 1 mutes again and channel 2 unmutes. Etc.

I hope you can help me. I'm beginner level Arduino and MaxMSP but I have some knowledge about programming. Most web oriented though. I'm also available on Skype or any other communication program.

Kind regards.

Source Audio's icon

I'll be glad to help You, but only if You accept to simplify the whole arduino gibberish.
You don't need all that stuff inside.
That's why it is not working.
So if You just upload the arduino code to arduino and use max patch,
it will work.
All You need is to send 2 POT values from Arduino and interpret that in Max.
This is all code it needs :
void setup() {Serial.begin(9600);}

void loop() {int Pot1 = analogRead(A0);int Pot2 = analogRead(A1);
Serial.print(Pot1); Serial.print(" "); Serial.println(Pot2);
delay(50); }

Then in Max :

Max Patch
Copy patch and select New From Clipboard in Max.

That gives pot 1 to switch between 0 -6 and pot 2 for volume 0 -100
That will give You simple idea how that works.
If You want to do all the switching in arduino, ok but let's wait
till You have this first one running, ok ?

Dylan de Bruijn's icon

Thanks for you quick reply! I meant no disrespect towards you. The code I used was provided by my school. I tested the code you provided and it works now. Thanks alot! What should I use for the channels?

Source Audio's icon

Hey - don't worry - I did not feel any kind of disrespect, and also I don't want
to force You into any direction, it is just that when one starts to learn, one should
start with simple and understandable steps, and what I saw in patches that were "provided"
to You is just the oposite, that's not a way to teach...
------
But let's get back to Your project, what do You mean by channels ?
Maybe how to switch all players ?
I would suggest using matrix because it can switch without clicks.
Another question is would You prefer to do switching in Arduino
(I mean mapping 0-1023 and sending that out) or to do all in Max ?
And at the end when You get that 12 position rotary switch,
how are You going to use it ?
Switching 12 Arduino inputs, or by resistor network ?

Dylan de Bruijn's icon

You are right, the code you provided is much clearer and documentation and reference helped me understand is so I get what you did now.

By channels I mean sound / music players. So I want 12 different players each with a mp3 file. I'm creating this project for people with dementia so they can use the radio like it was in the past. So each player plays something different. Classical music, news from the past, interviews, holiday music, dutch music, comedy etc.

All these players share a common volume that can be switched with Potmeter1. Potmeter 2 (rotary switch later) switches to the corresponding player when it clicks.

How can I implement a matrix?

For the rotary switch I wanted to use 12 digital inputs. Or is there an easier option?

I added my idea for the players in the patcher. I'm sure this can be simplified, but how?

Max Patch
Copy patch and select New From Clipboard in Max.


- Edit: provided image was too small sorry!

Source Audio's icon

Sorry, I have to leave till tomorrow, here is example with few players.
You can extend that. I'll be back tomorrow to continue...

Max Patch
Copy patch and select New From Clipboard in Max.

Source Audio's icon

12 pole rotary switch could be either "break before make"
or "make before brake". That is important difference.
In case of "make before brake" one gets 2 switches conducting
when moving between positions.
If You were to sample 12 Digital Inputs of Arduino to decide
which Audio file to play, You will have 2 values as long as switch
is between the positions. One can even park rotary switch
between positions if one wants to... well depending on hardware type.
On the other hand in case of "break before make" one has
no contact at all in betweeen positions.
To conclude - in both cases You have to make some logic to decide
what to do.
If You instead use 12 resistors network as voltage dividers, and measure output
on 1 Analog input, that would be another game.
Makes me think that a good linear pot would be a simpler solution,
one could even make some noise between stations to simulate radio.

Source Audio's icon

And here is 12 player patch, put right audio file names in.
mp3 playback is only available in max7
The switch is set from 0 - 12, try if it is precise enough to switch
12 players, I did using large linear fader - works fine.
0 turns all off

Max Patch
Copy patch and select New From Clipboard in Max.

Dylan de Bruijn's icon

Hey, thanks alot for your time and patience. On second thought a second pot would be better because the rotary switch is a little stiff. I tested it with the people with dementia and it's difficult for them to turn. I'm testing right now. I will respond back asap!

Source Audio's icon

If it is difficult for them to turn rotary switch, don't You think that
precisely adjusting a pot for 12 positions could also be a difficulty ?
Maybe You could make up / down press button.

Dylan de Bruijn's icon

It works perfectly! Thanks a TON! I would like to learn how you made it work so I'm going to experiment with it ;). Is it easy to make the noise longer between channels? I'm not sure yet how many channels I would like to add is that easy to change too?

Source Audio's icon

Number of channels possible depends on how precise one can adjust the pot.
You see the left scale object ? Saying {scale 0 1023 0 12}
look at the scale help file.
But one could also do different thing, like splitting values.
Lets say we want incoming 0 to mute all,
10 - 20 to play first audio, 20 -30 make noise ( simulate station not adjusted)
30 -40 play audio 2 and so on...
------------
Another question for You : You want all players to loop all the time
to avoid feeling of allways starting from the begining, is that right ?
One could use only 1 Audio player, and still simulate that behaviour.
Sfplay can preload large number of cued audio files, and quickly
switch between them. To avoid playing from beginning one could
randomly select start position on every new start.
Interested ?

Dylan de Bruijn's icon

Yes that is correct, I'm interested. If I change the scale do I only need to change select? Or do I need to change the whole patch?

Source Audio's icon

If You want to have 14 audio files, then You scale 0 1023 0 14.
and add players 13 & 14, with {sel 13} and {sel 14} I hope You understand it in the meanwile.
The idea of 1 player and many files - there are 2 options :
1 - would be to randomly select start time for every player
2 - start timer and measure elapsed time. When Player starts playing any file
position of the playback will be there as if the file was looping from the beginning
of the timer.
In both cases, one would have to make a list of audio files and their length.
The option 2 is maybe better, because one would have continuity when switching
between radio channels, just as what You have now, all files looping in individual players.
Let's say I'm hearing a Song, and just switch few seconds to next station, like weather report
If I switch back to the Song, it would play from where it would have been without interruption.
With random approach it would play from any position ...

Source Audio's icon

just to get You ready, this is coll format for loading files into sfplay:
1, open Classic.mp3 480;
2, preload 2 Opera.mp3 833;
3, preload 3 "News Channel.mp3" 664;
4, preload 4 "Ambient Sounds.mp3" 1294;

etc.
coll form is allways address comma data semicolon
the numbers at the end of data string should be length of each audio file in seconds
When You get infos on length like "4 min 44" do rather 4x60 + 44 = 284 - 1 = 283
1 second less.
Although max 7 can play mp3 files, sfinfo can't get mp3 length...
So You will end up having list of 12 or more audio file names and their length.
That should be saved as plain text so that coll can read it.
You can use something like Radio-Stations.txt
On start Max will read the file, preload audio files into sfplay
and get the lengths ready for adjusting play position when switching between stations.
------------------
Just let me know wenn You are ready to continue, I will upload example
for loading, switching etc