element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • Choose Another Store
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Personal Blogs
  • Members
  • More
Personal Blogs
Legacy Personal Blogs Simple Arduino Music Box: Chords
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: jc2048
  • Date Created: 28 May 2018 5:44 PM Date Created
  • Views 1419 views
  • Likes 8 likes
  • Comments 2 comments
  • ardintermediate
  • arduino_projects
  • music
  • arduino
  • music box
Related
Recommended

Simple Arduino Music Box: Chords

jc2048
jc2048
28 May 2018
image

Simple Music Maker

Enter Your Electronics & Design Project for Your Chance to Win a Fog Machine and a $100 Shopping Cart!

Back to The Project14 homepage image

Project14 Home
Monthly Themes
Monthly Theme Poll

 

"What harmony is this? My good friends, hark!"


Alonso. Tempest[III,3]. William Shakespeare.

 

Previous blogs

 

A Simple Arduino Music Box

Simple Arduino Music Box: Voices

 

Introduction

 

This is more on the Arduino music box that I did for the Project14  Simple Music Maker competition.

 

The original project played one note at a time. That's a bit tame - let's see if we can manage some polyphony and play some

chords. Although playing chords might seem to be considerably more complex, in practice it is quite easy and naturally falls

out of what I've done so far. To get multiple notes playing I just need a table index for each note and the appropriate step

size to give the required note. Then I simply sum the results and scale for the output. It is more processing, but it might

work, so let's give it a try.

 

The Sketch

 

Here's the sketch. The include at the start is

 

#include <Arduino.h>

 

/* Arduino Music Box: Chords */
#include <Arduino.h>
volatile unsigned int tableOffset1 = 0; // wave table index, note 1
volatile unsigned int tableOffset2 = 0; // wave table index, note 2
volatile unsigned int tableOffset3 = 0; // wave table index, note 3
volatile unsigned int tableOffset4 = 0; // wave table index, note 3
volatile unsigned int tableStep1 = 0;   // wave table step, note 1
volatile unsigned int tableStep2 = 0;   // wave table step, note 1
volatile unsigned int tableStep3 = 0;   // wave table step, note 1
volatile unsigned int tableStep4 = 0;   // wave table step, note 1
unsigned int noteTime = 0xc35;          // note duration count
unsigned int outputValue = 0;           // 
int i=0;
// Twinkle, Twinkle, Little Star
// Each line is four notes and a duration. 0 if no note.
// Line of 5 zeroes marks the end.
unsigned int tuneNotes[] = {
    343, 229, 144, 0, 0x4000,
    385, 229, 153, 0, 0x4000,
    343, 229, 144, 0, 0x4000,
    385, 229, 153, 0, 0x4000,
//
    343, 229, 144, 0, 0x4000,
    385, 216, 153, 0, 0x4000,
    343, 229, 144, 0, 0x8000,
//
    343, 229, 192, 0, 0x4000,
    306, 229, 0, 0, 0x4000,
    288, 229, 171, 0, 0x4000,
    229, 144, 0, 0, 0x4000,
//
    192, 162, 0, 0, 0x4000,
    306, 216, 128, 0, 0x4000,
    288, 229, 114, 0, 0x8000,
//
    171, 85, 0, 0, 0x4000,
    192, 96, 0, 0, 0x4000,
    229, 114, 0, 0, 0x4000,
    257, 128, 0, 0, 0x4000,
//
    288, 144, 0, 0, 0x4000,
    306, 162, 0, 0, 0x4000,
    343, 171, 0, 0, 0x8000,
//
    343, 216, 171, 144, 0x4000,
    288, 0, 0, 0, 0x4000,
    229, 192, 144, 96, 0x4000,
    306, 192, 162, 64, 0x4000,
//
    257, 216, 162, 108, 0x4000,
    257, 216, 162, 48, 0x4000,
    229, 144, 64, 0, 0x8000,
//    
    0,0,0,0,0
    };
//
//  --- Wave table - generated by waveTable.exe 
//
unsigned int waveTable[512] = {
   0x8000,0x862d,0x8c57,0x927a,0x9890,0x9e98,0xa48c,0xaa69,0xb02c,0xb5d1,0xbb55,0xc0b4,0xc5eb,0xcaf7,0xcfd5,0xd483,
   0xd8fd,0xdd41,0xe14d,0xe520,0xe8b6,0xec0e,0xef27,0xf1ff,0xf496,0xf6ea,0xf8fa,0xfac6,0xfc4f,0xfd93,0xfe93,0xff4f,
   0xffc8,0xfffe,0xfff4,0xffa8,0xff1e,0xfe57,0xfd54,0xfc17,0xfaa2,0xf8f8,0xf71a,0xf50c,0xf2d0,0xf069,0xedd9,0xeb24,
   0xe84d,0xe556,0xe243,0xdf17,0xdbd6,0xd883,0xd520,0xd1b2,0xce3c,0xcac0,0xc743,0xc3c8,0xc051,0xbce2,0xb97e,0xb628,
   0xb2e2,0xafb0,0xac94,0xa990,0xa6a8,0xa3dc,0xa130,0x9ea5,0x9c3e,0x99fb,0x97de,0x95e8,0x941b,0x9278,0x90fe,0x8fb0,
   0x8e8d,0x8d95,0x8cc8,0x8c27,0x8bb0,0x8b64,0x8b42,0x8b49,0x8b77,0x8bcd,0x8c47,0x8ce6,0x8da7,0x8e89,0x8f8a,0x90a8,
   0x91e1,0x9332,0x949a,0x9617,0x97a5,0x9943,0x9aee,0x9ca3,0x9e61,0xa024,0xa1eb,0xa3b1,0xa577,0xa737,0xa8f1,0xaaa2,
   0xac48,0xade0,0xaf69,0xb0e0,0xb243,0xb391,0xb4c8,0xb5e6,0xb6eb,0xb7d3,0xb89f,0xb94e,0xb9de,0xba4e,0xba9f,0xbad0,
   0xbae0,0xbad0,0xba9f,0xba4e,0xb9de,0xb94e,0xb89f,0xb7d3,0xb6eb,0xb5e6,0xb4c8,0xb391,0xb243,0xb0e0,0xaf69,0xade0,
   0xac48,0xaaa2,0xa8f1,0xa737,0xa577,0xa3b1,0xa1eb,0xa024,0x9e61,0x9ca3,0x9aee,0x9943,0x97a5,0x9617,0x949a,0x9332,
   0x91e1,0x90a8,0x8f8a,0x8e89,0x8da7,0x8ce6,0x8c47,0x8bcd,0x8b77,0x8b49,0x8b42,0x8b64,0x8bb0,0x8c27,0x8cc8,0x8d95,
   0x8e8d,0x8fb0,0x90fe,0x9278,0x941b,0x95e8,0x97de,0x99fb,0x9c3e,0x9ea5,0xa130,0xa3dc,0xa6a8,0xa990,0xac94,0xafb0,
   0xb2e2,0xb628,0xb97e,0xbce2,0xc051,0xc3c8,0xc743,0xcac0,0xce3c,0xd1b2,0xd520,0xd883,0xdbd6,0xdf17,0xe243,0xe556,
   0xe84d,0xeb24,0xedd9,0xf069,0xf2d0,0xf50c,0xf71a,0xf8f8,0xfaa2,0xfc17,0xfd54,0xfe57,0xff1e,0xffa8,0xfff4,0xffff,
   0xffc8,0xff4f,0xfe93,0xfd93,0xfc4f,0xfac6,0xf8fa,0xf6ea,0xf496,0xf1ff,0xef27,0xec0e,0xe8b6,0xe520,0xe14d,0xdd41,
   0xd8fd,0xd483,0xcfd5,0xcaf7,0xc5eb,0xc0b4,0xbb55,0xb5d1,0xb02c,0xaa69,0xa48c,0x9e98,0x9890,0x927a,0x8c57,0x862d,
   0x8000,0x79d2,0x73a8,0x6d85,0x676f,0x6167,0x5b73,0x5596,0x4fd3,0x4a2e,0x44aa,0x3f4b,0x3a14,0x3508,0x302a,0x2b7c,
   0x2702,0x22be,0x1eb2,0x1adf,0x1749,0x13f1,0x10d8,0x0e00,0x0b69,0x0915,0x0705,0x0539,0x03b0,0x026c,0x016c,0x00b0,
   0x0037,0x0001,0x000b,0x0057,0x00e1,0x01a8,0x02ab,0x03e8,0x055d,0x0707,0x08e5,0x0af3,0x0d2f,0x0f96,0x1226,0x14db,
   0x17b2,0x1aa9,0x1dbc,0x20e8,0x2429,0x277c,0x2adf,0x2e4d,0x31c3,0x353f,0x38bc,0x3c37,0x3fae,0x431d,0x4681,0x49d7,
   0x4d1d,0x504f,0x536b,0x566f,0x5957,0x5c23,0x5ecf,0x615a,0x63c1,0x6604,0x6821,0x6a17,0x6be4,0x6d87,0x6f01,0x704f,
   0x7172,0x726a,0x7337,0x73d8,0x744f,0x749b,0x74bd,0x74b6,0x7488,0x7432,0x73b8,0x7319,0x7258,0x7176,0x7075,0x6f57,
   0x6e1e,0x6ccd,0x6b65,0x69e8,0x685a,0x66bc,0x6511,0x635c,0x619e,0x5fdb,0x5e14,0x5c4e,0x5a88,0x58c8,0x570e,0x555d,
   0x53b7,0x521f,0x5096,0x4f1f,0x4dbc,0x4c6e,0x4b37,0x4a19,0x4914,0x482c,0x4760,0x46b1,0x4621,0x45b1,0x4560,0x452f,
   0x451f,0x452f,0x4560,0x45b1,0x4621,0x46b1,0x4760,0x482c,0x4914,0x4a19,0x4b37,0x4c6e,0x4dbc,0x4f1f,0x5096,0x521f,
   0x53b7,0x555d,0x570e,0x58c8,0x5a88,0x5c4e,0x5e14,0x5fdb,0x619e,0x635c,0x6511,0x66bc,0x685a,0x69e8,0x6b65,0x6ccd,
   0x6e1e,0x6f57,0x7075,0x7176,0x7258,0x7319,0x73b8,0x7432,0x7488,0x74b6,0x74bd,0x749b,0x744f,0x73d8,0x7337,0x726a,
   0x7172,0x704f,0x6f01,0x6d87,0x6be4,0x6a17,0x6821,0x6604,0x63c1,0x615a,0x5ecf,0x5c23,0x5957,0x566f,0x536b,0x504f,
   0x4d1d,0x49d7,0x4681,0x431d,0x3fae,0x3c37,0x38bc,0x353f,0x31c3,0x2e4d,0x2adf,0x277c,0x2429,0x20e8,0x1dbc,0x1aa9,
   0x17b2,0x14db,0x1226,0x0f96,0x0d2f,0x0af3,0x08e5,0x0707,0x055d,0x03e8,0x02ab,0x01a8,0x00e1,0x0057,0x000b,0x0000,
   0x0037,0x00b0,0x016c,0x026c,0x03b0,0x0539,0x0705,0x0915,0x0b69,0x0e00,0x10d8,0x13f1,0x1749,0x1adf,0x1eb2,0x22be,
   0x2702,0x2b7c,0x302a,0x3508,0x3a14,0x3f4b,0x44aa,0x4a2e,0x4fd3,0x5596,0x5b73,0x6167,0x676f,0x6d85,0x73a8,0x79d2};
void setup() {
  
  // set the digital pins as outputs:
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  
  pinMode(8, OUTPUT);     // test output
 
  // timer 2 set up
  cli();                  // disable interrupts
  TCCR2A = 0;             // control register all 0
  TCCR2B = 0;             // control register all 0
  TCNT2 = 0;              // set count to 0
//  OCR2A = 159;            // period = 160 x 1/16MHz = 10uS [100ksps]
  OCR2A = 239;            // period = 240 x 1/16MHz = 15uS [66.6ksps]
  TCCR2A |= (1 << WGM21); // mode is clear on match
  TCCR2B |= (1 << CS20);  // no prescaler   
  TIMSK2 |= (1 << OCIE2A);  // enable interrupt on match
  sei();                  // enable interrupts
}
ISR(TIMER2_COMPA_vect) {
  PORTB |= 0x01;   
  if(tableStep1 == 0) {
    PORTD = 0x80;
    noteTime = noteTime - 1;
    if(noteTime==0) {
      tableStep1 = tuneNotes[i++];
      tableStep2 = tuneNotes[i++];
      tableStep3 = tuneNotes[i++];
      tableStep4 = tuneNotes[i++];
      noteTime = tuneNotes[i++];
      tableOffset1 = 0;
      tableOffset2 = 0;
      tableOffset3 = 0;
      }
    }
  else {
    tableOffset1 = tableOffset1 + tableStep1;
    tableOffset2 = tableOffset2 + tableStep2;
    tableOffset3 = tableOffset3 + tableStep3;
    tableOffset4 = tableOffset4 + tableStep4;
    outputValue = waveTable[tableOffset1 >> 7] >> 8;
    outputValue = outputValue + (waveTable[tableOffset2 >> 7] >> 8);
    outputValue = outputValue + (waveTable[tableOffset3 >> 7] >> 8);
    outputValue = outputValue + (waveTable[tableOffset4 >> 7] >> 8);
    PORTD = outputValue >> 2;
    noteTime = noteTime - 1;
    if(noteTime==0) {
      tableOffset1 = 0;
      tableOffset2 = 0;
      tableOffset3 = 0;
      tableOffset4 = 0;
      tableStep1 = 0;
      tableStep2 = 0;
      tableStep3 = 0;
      tableStep4 = 0;
      noteTime = 0xc35;
      if (tuneNotes[i]==0)
        i=0;
      }
    }
    PORTB &= 0xFE; 
}
void loop() {
}

 

It's much as I had before except everything is done four times over - four step additions and four look-ups. The division by

four of the summed values, to scale the final result, is done with a shift. It does work, but the time it takes is around

the same as the 10uS that the timer period was set to. To give it a bit more space, I've slowed the sample rate down to

66.6ksps (15uS). That transposes all my notes down and slows the note durations but it still sounds ok (I'm feeling too lazy

to go back and recalculate them). The relationships between the notes remain the same, so unless you have perfect pitch you

won't know that the notes are now wrong.

 

The way I knew that it was taking all of the processing time was to set an output pin at the start and reset it at the end

of the interrupt code. That's the write to PORTB that you can see in the code. Here's the scope trace, but with a longer

timer period. Bear in mind that the interrupt needs time for entry and exit too, so it was over-running the 10uS.

 

image

 

An Example

 

And here's what it sounds like. This is the Twinkle, Twinkle tune that I used for the original music box but played with

chords rather than just the melody line. It's now much more complex in sound, even though it's all a bit basic in hardware

terms (keep in mind we're at the grunge end of the hardware spectrum, not the hi-fi end).

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

I'm quite proud of that, even though it is just a silly piece of hackery.

 

Next thing to look at is adding an envelope generator: Simple Arduino Music Box: Envelopes

  • Sign in to reply

Top Comments

  • genebren
    genebren over 5 years ago +1
    Each step takes your project a step further. It will be fun to see where you go with this. Gene
  • jc2048
    jc2048 over 5 years ago in reply to genebren +1
    Every journey starts with the first step. Then you get diverted and go somewhere else. I'm currently wondering why transistors got called 'transistors' rather than 'transductors'. Steps: sound envelopes…
  • jc2048
    jc2048 over 5 years ago in reply to genebren

    Every journey starts with the first step. Then you get diverted and go somewhere else.

     

    I'm currently wondering why transistors got called 'transistors' rather than 'transductors'.

     

    Steps:

     

    sound envelopes -> hardware approach -> voltage-controlled amplifier -> using variation of transconductance of a transistor with varying collector current -> bingo! a 'Music Box' blog combined with a 'Transistors' blog

     

    Now I've just got to do it. Perhaps at the weekend if I can find some time.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • genebren
    genebren over 5 years ago

    Each step takes your project a step further.  It will be fun to see where you go with this.

    Gene

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • Facebook
  • Twitter
  • linkedin
  • YouTube