Go Down

Topic: polyphonic piano with arduino?? (Read 10808 times) previous topic - next topic

falohao

I'm implementing a project which is polyphonic plus monophonic piano.
The 8-key monophonic piano has been done already. But I have some questions :'(.

My supervisor have just said that I may implement multi-key sensing first, is that right? Or I still keep doing polyphony?

I'm so confused!! :-/

BTW, any link suggested for me? I have no idea in those 2 parts :-[

Grumpy_Mike

Quote
I'm so confused!

So am I.
Quote
that I may implement multi-key sensing first, is that right? Or I still keep doing polyphony?

Can you explain this more it don't make sense to me. What are you doing in the sketch and what do you want to do?

In order to do polyphony you need to detect multiple keys otherwise there is no way to get it to produce a polyphonic sound. I don't understand what you are asking.

falohao

I produced a piano (it means 1 note only can be played at a certain time). I want to produce a piano with polyphony (it means 1 or more than 1 note can be played at same time).

But I don't know how to write a program that can be multi-key sensing...
,also dont know how to make it polyphonic.

I've just read the Tone.cpp, it talks about timers, I saw many polyphony project used it. :'(

falohao

do this link talk about multi-key sensing?

or just use a mux for connect inputs which are more than pins built on the arduino?

cr0sh@inexo

I've thought about this on occasion.

Probably the easiest way to do the sensing of the keys would be to use parallel/serial shift latching registers - basically, the inputs on the registers (parallel) are latched over (via a digital write), then the bits are clocked out (via a clock line and a data line) to the Arduino; you would end up with a long string of bits that you can then decide what to do with.

Of course, at the time, I was thinking "now how would I incorporate pressure sensing" - then I realized I had a robot project in progress...

:'(

falohao

sorry..

is http://www.arduino.cc/en/Tutorial/ShiftIn talk about the register u said?

Grumpy_Mike

Quote
talk about the register u said?


Yes.

You have to work out what sort of circuit you need for the multiple keys before you consider the programming of it. How many keys do you need? What have you got already?
Do some reading:-
http://www.arduino.cc/playground/Main/KeypadTutorial
The Monome is a project that supports multiple key presses, my version of it is here:-
http://www.thebox.myzen.co.uk/Hardware/Econo_Monome.html
There are amny more at:-
http://monome.org/

cr0sh@inexo

#7
Feb 04, 2010, 09:24 pm Last Edit: Feb 04, 2010, 09:29 pm by cr0sh@inexo Reason: 1
Let's say you wanted to do 4-note polyphonic output, with the shift-register concept (as mike said, what you found is a good example). So, you shift in your bits, and as you are counting your bits (each one a different key/note), as you hit a bit that is set, note its position (or note), and continue, until you have four positions/notes defined; stop shifting at this point (and maybe clear the register in some manner).

Now you know which notes to play, so pick four PWM channels/pins, set them accordingly to output the waveforms for the tones of the notes being played.

The outputs of these pins should then be run into a simple mixer circuit (plenty to be found on the net) before output to the amplifier and speaker.

You'll also have to code and account for release of the keys...

This is one way to do it; another way would be to have the Arduino mix the four waveforms in realtime, then output the mixed waveform to a DAC, then to the amp/speaker. Doing this method would allow you to set up "wavetables" holding different simple patterns (square, sawtooth, triangle, sine); you could even conceivably write code to simulate ASDR envelopes for true FM output.

There probably isn't enough memory, though, on a 168/328 to mix and playback samples - you might be able to get away with it using an external I2C/SPI RAM/EEPROM or and SD card interface. That, or move to a larger Atmel device (644?)...

Dnstje

#8
Feb 23, 2010, 11:30 pm Last Edit: Feb 23, 2010, 11:30 pm by Dnstje Reason: 1
err, Tone can only do 3 tones at the same time right? because of the limited hardware timer. (on the ATMEGA328)

falohao

/*
 Piano

 Using 8 push buttons attached to pins 2 thou 9 and a speaker
 attached to pin 13. Create a C minor piano. The button on pin
 2 will play a low C and the button on pin 9 will play middle c.
 
 The Circuit.
   * push buttons attached to pins 2 thou 9 from ground
   * speaker attached to pin 13 from ground
   
 With this basic setup you can easily add 3 more notes. You can
 also go in and change the frequency to get the notes you desire.
 
 created 20 Jan 2010
 by digimike

*/

boolean button[] = {2, 3, 4};  //create array for button pins
boolean speakerpin = 13;  //sets speaker pin
boolean buttonset = 0;  //variable for reading button push
int tone = 0;
void setup() {
 // set all pins to output
 pinMode(speakerpin, OUTPUT);
 for(int x=0; x<8; x++) {
   pinMode(button
  • , OUTPUT);
     }
     // buttons are in the high position
     for(int x=0; x<8; x++) {
       digitalWrite(button
  • , HIGH);
     }
    }

    void loop()
    {
     // checks the state of each button
     for(int x=0; x<8; x++) {
       buttonset = digitalRead(button
  • );
     
       if(buttonset == LOW && button
  • == 2){ // if button on pin 2 is pressed
         tone = 1050;    //stores the note's wavelength to be played.
       }
       if(buttonset == LOW && button
  • == 3) {
         tone = 940;
       }
       if(buttonset == LOW && button
  • == 4) {
         tone = 837;
       }
       
     }
     while(tone > 0) {    // as long as there is a not to be played
     digitalWrite(speakerpin, HIGH);    // turn on 5V to speaker
     delayMicroseconds(tone);    // delay the designated wavelength in ms
     digitalWrite(speakerpin, LOW);    // turn off speaker
     delayMicroseconds(tone);    // delay the designated wavelength in ms
     tone = 0;   // resets tone variable to 0 so the tone dosn't play constantly
     }
     
    }
     

    The above is the sketch, how can I hold/save the key whenever they are held down. Also, how can I hold/save tones then output to 4 channels. I want to produce a simple polyphonic elec. piano only, so i don't want to use "DAC" method. Please dive me some directions, thanks to all..

PaulS

Quote
how can I hold/save the key whenever they are held down.


This code:
Code: [Select]
buttonset = digitalRead(button[x]);

Is reading the current state of the switch on pin button
  • . The switch is being held down if it's state is the same as the last time you read it.

    This means that you need to save the state of the button, in an array, and compare the current reading to the previous reading.

    Questions: You are reading the state of 8 pins, whose numbers are stored in an array of length 3. Why does the array length not match the number of pins to read? Why is the type of the array boolean? That is not compatible with the data being stored in the array.

    Why are speakerpin and buttonset booleans? The values being stored in these variables is not true or false.
The art of getting good answers lies in asking good questions.

falohao

SOrry Pauls...

I want to store states of more than one keys. Then output to different channels. Just like a polyphonic elec. piano.
eg.

Suppose 3 keys are connected to Arduino,

Key 1 (held down)~>Store
(keep on scanning)
Key 2 (Normal state)~>ignore
(keep on scanning)
Key 3 (held down)~>store

Play tones which were mapped to different keys

Then output to first channel and third channel.

I want to implement my product likes above.
Can someone help me?

PaulS

The first thing you need to do is use variables of the correct type. The pin numbers are NOT boolean. If size is an issue, you can use byte. If not, use int.

The second thing you need to do is make the loops that access array data match the size of the array being accessed. Don't try to access button[5] when button is declared an array of size 3.

The third thing you need to do is to create another array to store the state of the switches.

Code: [Select]
byte switchState[3];

In the loop that reads the state of button
  • , compare the value read (buttonset) to the previous state, in switchState
  • . If they are different the switch was pressed and is now released or it was released and is now pressed. It appears that you want to ignore these cases. So, what's left is the cases where the previous switch state is the same as the current state. That happens when the switch is pressed and was pressed or when the button was released and is released.

    It appears as though you only want to handle the first case, so check that the states are the same and either is LOW.

    At the end of the loop, store the current state of the switch (buttonset) in the array (switchState
  • ).
The art of getting good answers lies in asking good questions.

falohao

Pauls

Pardon me....

Can you give me some examples about it. Actually, I don't understand all the things you said.

I'm a newbie in Arduino.


PaulS

In your code, change these three lines:
Code: [Select]
boolean button[] = {2, 3, 4};  //create array for button pins
boolean speakerpin = 13;  //sets speaker pin
boolean buttonset = 0;  //variable for reading button push


to:
Code: [Select]
byte button[] = {2, 3, 4};  //create array for button pins
byte speakerpin = 13;  //sets speaker pin
byte buttonset = 0;  //variable for reading button push
byte switchState[3];


Change all of these lines (there are at least 3):
Code: [Select]
for(int x=0; x<8; x++) {

to:
Code: [Select]
for(int x=0; x<3; x++) {

Change this:
Code: [Select]
for(int x=0; x<8; x++) {
  buttonset = digitalRead(button[x]);

  if(buttonset == LOW && button[x] == 2){ // if button on pin 2 is pressed
    tone = 1050;    //stores the note's wavelength to be played.
  }
  if(buttonset == LOW && button[x] == 3) {
    tone = 940;
  }
  if(buttonset == LOW && button[x] == 4) {
    tone = 837;
  }
 
}


to this:

Code: [Select]

tone = 0;
for(int x=0; x<8; x++)
{
  buttonset = digitalRead(button[x]);

  if(buttonState[x] == buttonset)
  {
     if(buttonset == LOW)
     {
        if(x == 0)
        { // if button on pin 2 is pressed
           tone = 1050;    //stores the note's wavelength to be played.
        }
        if(x == 1)
        {
           tone = 940;
        }
        if(x == 2)
        {
           tone = 837;
        }
     }
  }

  buttonState[x] = buttonset;
}


At the end of this loop, tone will be 0 if no switch that was pressed last time is still pressed. Otherwise tone will have a value based on the highest numbered pin that is still being held down.

Notice that the value of tone no longer depends on the pin number. Instead, it depends on the order of pins defined in the array. You can change the pins in the array, and the tone will now follow.

Before, if you moved the switches to different pins, you'd need to change the array and the if statements to match.
The art of getting good answers lies in asking good questions.

Go Up