element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • 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 Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • 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
  • Settings
Personal Blogs
  • Community Hub
  • More
Personal Blogs
Legacy Personal Blogs Simple Arduino Music Box: Chimes
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: jc2048
  • Date Created: 5 Jun 2018 1:18 PM Date Created
  • Views 5918 views
  • Likes 8 likes
  • Comments 8 comments
  • ardintermediate
  • arduino_projects
  • chime
  • uno
  • music
  • arduino
  • music box
Related
Recommended

Simple Arduino Music Box: Chimes

jc2048
jc2048
5 Jun 2018

Like sweet bells jangled, out of tune and harsh;

 

Ophelia, Hamlet [III, 1], William Shakespeare

 

Previous blogs:

A Simple Arduino Music Box

Simple Arduino Music Box: Voices

Simple Arduino Music Box: Chords

Simple Arduino Music Box: Envelopes

 

Introduction

 

I'm discovering that, if you build a simple, programmable device to make sound, you can't stop playing with it. With each of these blogs I say to myself that it's going to be the last, and yet here I am doing another one.

 

The original project was supposed to be a music box, yet all the sounds I've created so far sound more like an electronic organ than a traditional music box. This blog is an attempt to make a sound that has more of the quality of a chime or bell, or at the very least something metallic and tinkly. It's not all that successful, though the resulting sound has some of the qualities I was after. I've discovered, in doing these blogs, that creating imitations of real sounds is very difficult.

 

Instruments based on a column of air or a vibrating string naturally produce overtones that are related in a simple way to the fundamental (harmonics) [though that doesn't mean that there aren't other, more complex, components to the sound]. With other kinds of instruments things are immediately more complex. Bells, chimes, triangles, and other percussive instruments are 3-D structures and support many resonant modes which aren't necessarily related. So, if I want such a sound, I need to move away from simple harmonics and consider partials (overtones without an integer relationship to a fundamental). I can't get that from manipulating the waveshape of a single cycle, in the way that I did for harmonics, instead I have to treat them as separate sounds like I did with chords. I'm going to have to generate them separately and that's going to leave me very, very short of time in the interrupt routine - indeed, I know from what I did before that it won't run in the time so, to stop it over-running, I'm going to extend the timer period to reduce the sample rate to 62,500sps (15uS for the period between interrupts).

 

My starting point was some measured partials that I found in a book on acoustics by Benade[1] (thank you, Colchester Public Library). They were for a clock chime which was intended to mimic a bell.

 

P = 5-10cps (inaudible)
Q = 180cps (1)
Ra = 525cps (10)
Rb = 530cps (6.3)
S = 1063cps (22)
T = 1771cps (45)

 

He labels his overtones with letters starting at 'P'. The number in brackets is the intensity relative to Q, so you can see that the higher partials are considerably louder than the lower ones, and the lowest is so low in frequency that it can't be heard.

I don't have time to generate all those partials, so as an experiment I'm going to choose four [the top four] and see how it sounds. I also don't have the dynamic range (with only 8 bits) nor the processing time to do the maths to scale the relative amplitudes properly, so it's going to be a very rough and ready approximation. But the great thing about experimenting with music like this is that once the hardware platform is built it becomes very easy and quick to try things out and just see how they sound (and if it sounds good, it is good, irrespective of whether it's the right way to do something). To get the different notes I simply transpose the frequencies of all of the partials by 2^(1/12) for each semitone in the usual way for an equally-tempered scale. I've also moved everything up an octave by multiplying all the frequencies by two.

 

For the envelope, I'm going for a fast attack and a long decay, with no hold in between - an envelope shape that's common for percussive instruments where all the energy driving the system goes in quickly at the start and then steadily dissipates.

 

The Hardware

 

The hardware is still the same as for the initial Simple Music Box, just a simple DAC, a filter, and a crude amplifier to drive a loudspeaker.

 

The Sketch

 

Here's the experimental Arduino Uno sketch. It works but it's not neat and tidy code - for instance, part of the state machine is skipped because I don't need the hold period. As before, it's specific to the Uno and may need to be reworked for a different platform.

 

 

/* Arduino Music Box */
/* chimes by additive synthesis of partials */
#include <Arduino.h>
unsigned char noteState = 0;
unsigned char preScale = 0;
unsigned char envelopeValue = 0;
unsigned int noteTime = 0xc35;          // note duration count
unsigned int tableStep1 = 0;            // wave table step size
unsigned int tableStep2 = 0;
unsigned int tableStep3 = 0;
unsigned int tableStep4 = 0;
unsigned int tableOffset1 = 0;          // wave table index
unsigned int tableOffset2 = 0;
unsigned int tableOffset3 = 0;
unsigned int tableOffset4 = 0;
signed char waveValue1 = 0;             // value read from table
signed char waveValue2 = 0;
signed char waveValue3 = 0;
signed char waveValue4 = 0;
signed char summedValue = 0;
int i=0;
//    1101,1111,2229,3716,0x0010,   //C
//    1166,1178,2362,3937,0x0010,   //C#
//    1236,1248,2502,4171,0x0010,   //D  
//    1309,1322,2651,4419,0x0010,   //Eb
//    1387,1400,2809,4682,0x0010,   //E
//    1470,1484,2976,4960,0x0010,   //F
//    1557,1572,3153,5255,0x0010,   //F# 
//    1650,1665,3340,5568,0x0010,   //G 
//    1748,1764,3539,5899,0x0010,   //G#
//    1852,1869,3749,6250,0x0010,   //A
//    1962,1980,3972,6621,0x0010,   //Bb
//    2078,2098,4208,7015,0x0010,   //B
unsigned int tuneNotes[] = {
    1387,1400,2809,4682,0x0010,   //E
    1852,1869,3749,6250,0x0010,   //A
    1852,1869,3749,6250,0x0010,   //A
    2078,2098,4208,7015,0x0010,   //B
    1166,1178,2362,3937,0x0010,   //C#
    1852,1869,3749,6250,0x0010,   //A
    1166,1178,2362,3937,0x0010,   //C#
    2078,2098,4208,7015,0x0010,   //B
    1748,1764,3539,5899,0x0010,   //G#
    1852,1869,3749,6250,0x0010,   //A
    1852,1869,3749,6250,0x0010,   //A
    2078,2098,4208,7015,0x0010,   //B
    1166,1178,2362,3937,0x0010,   //C#
    1852,1869,3749,6250,0x0010,   //A
    1852,1869,3749,6250,0x0010,   //A
    1748,1764,3539,5899,0x0010,   //G#
    1387,1400,2809,4682,0x0010,   //E
    1852,1869,3749,6250,0x0010,   //A
    1852,1869,3749,6250,0x0010,   //A
    2078,2098,4208,7015,0x0010,   //B
    1166,1178,2362,3937,0x0010,   //C#
    1236,1248,2502,4171,0x0010,   //D  
    1166,1178,2362,3937,0x0010,   //C#
    2078,2098,4208,7015,0x0010,   //B
    1852,1869,3749,6250,0x0010,   //A
    1748,1764,3539,5899,0x0010,   //G#
    1387,1400,2809,4682,0x0010,   //E
    1557,1572,3153,5255,0x0010,   //F# 
    1748,1764,3539,5899,0x0010,   //G#
    1852,1869,3749,6250,0x0010,   //A
    1852,1869,3749,6250,0xc000,   //A
    0,0,0,0
    };
//
//  --- Wave table - generated by waveTable.exe 
//
signed char waveTable[512] = {
   0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3b,
   0x3f,0x42,0x46,0x49,0x4d,0x50,0x53,0x56,0x59,0x5c,0x5e,0x61,0x64,0x66,0x68,0x6b,
   0x6d,0x6f,0x70,0x72,0x74,0x75,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7d,0x7e,0x7e,
   0x7e,0x7e,0x7f,0x7e,0x7e,0x7e,0x7e,0x7d,0x7c,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,
   0x74,0x73,0x72,0x70,0x6f,0x6d,0x6b,0x6a,0x68,0x66,0x64,0x63,0x61,0x5f,0x5d,0x5b,
   0x59,0x57,0x55,0x53,0x51,0x4f,0x4d,0x4b,0x49,0x47,0x45,0x43,0x41,0x3f,0x3d,0x3b,
   0x3a,0x38,0x36,0x34,0x33,0x31,0x30,0x2e,0x2d,0x2b,0x2a,0x28,0x27,0x26,0x25,0x23,
   0x22,0x21,0x20,0x1f,0x1f,0x1e,0x1d,0x1c,0x1b,0x1b,0x1a,0x1a,0x19,0x19,0x18,0x18,
   0x18,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x17,0x17,0x17,0x17,0x17,
   0x17,0x17,0x17,0x17,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x19,0x19,0x19,0x19,0x19,
   0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x19,0x19,
   0x19,0x19,0x19,0x18,0x18,0x18,0x18,0x17,0x17,0x17,0x16,0x16,0x15,0x15,0x14,0x14,
   0x14,0x13,0x13,0x12,0x12,0x11,0x11,0x10,0x0f,0x0f,0x0e,0x0e,0x0d,0x0d,0x0c,0x0c,
   0x0b,0x0b,0x0a,0x0a,0x09,0x09,0x08,0x08,0x07,0x07,0x06,0x06,0x05,0x05,0x05,0x04,
   0x04,0x03,0x03,0x03,0x03,0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
   0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfc,0xfc,0xfc,0xfc,
   0xfb,0xfb,0xfa,0xfa,0xfa,0xf9,0xf9,0xf8,0xf8,0xf7,0xf7,0xf6,0xf6,0xf5,0xf5,0xf4,
   0xf4,0xf3,0xf3,0xf2,0xf2,0xf1,0xf1,0xf0,0xf0,0xef,0xee,0xee,0xed,0xed,0xec,0xec,
   0xeb,0xeb,0xeb,0xea,0xea,0xe9,0xe9,0xe8,0xe8,0xe8,0xe7,0xe7,0xe7,0xe7,0xe6,0xe6,
   0xe6,0xe6,0xe6,0xe6,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,
   0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,
   0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,
   0xe7,0xe7,0xe7,0xe6,0xe6,0xe5,0xe5,0xe4,0xe4,0xe3,0xe2,0xe1,0xe0,0xe0,0xdf,0xde,
   0xdd,0xdc,0xda,0xd9,0xd8,0xd7,0xd5,0xd4,0xd2,0xd1,0xcf,0xce,0xcc,0xcb,0xc9,0xc7,
   0xc5,0xc4,0xc2,0xc0,0xbe,0xbc,0xba,0xb8,0xb6,0xb4,0xb2,0xb0,0xae,0xac,0xaa,0xa8,
   0xa6,0xa4,0xa2,0xa0,0x9e,0x9c,0x9b,0x99,0x97,0x95,0x94,0x92,0x90,0x8f,0x8d,0x8c,
   0x8b,0x89,0x88,0x87,0x86,0x85,0x84,0x83,0x83,0x82,0x81,0x81,0x81,0x81,0x80,0x81,
   0x81,0x81,0x81,0x82,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x8a,0x8b,0x8d,0x8f,0x90,
   0x92,0x94,0x97,0x99,0x9b,0x9e,0xa1,0xa3,0xa6,0xa9,0xac,0xaf,0xb2,0xb6,0xb9,0xbd,
   0xc0,0xc4,0xc7,0xcb,0xcf,0xd3,0xd7,0xdb,0xdf,0xe3,0xe7,0xeb,0xef,0xf3,0xf7,0xfb};
   
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);     // for debug
  // 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 = 255;            // period = 160 x 1/16MHz = 10uS
  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;
  switch(noteState) {
    case 0:                           // inter-note gap
      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;
        tableOffset4 = 0;
        envelopeValue = 0;
        preScale = 3;
        noteState = 1;
        }
      break;
    case 1:                           // attack
      tableOffset1 = tableOffset1 + tableStep1;
      tableOffset2 = tableOffset2 + tableStep2;
      tableOffset3 = tableOffset3 + tableStep3;
      tableOffset4 = tableOffset4 + tableStep4;
      waveValue1 = (waveTable[tableOffset1 >> 7]) >> 4;
      waveValue2 = (waveTable[tableOffset2 >> 7]) >> 4;
      waveValue3 = (waveTable[tableOffset3 >> 7]) >> 2;
      waveValue4 = (waveTable[tableOffset4 >> 7]) >> 1;
      summedValue = waveValue1 + waveValue2 + waveValue3 + waveValue4;
      PORTD = (((signed int)(summedValue * envelopeValue)) >> 8) + 0x80;
      preScale--;
      if(preScale==0) {
        preScale = 2;
        if(envelopeValue != 255) {
          envelopeValue++;
          }
        else {
          noteState = 3;
          }
        }
      break;
    case 2:                           // hold
      tableOffset1 = tableOffset1 + tableStep1;
      tableOffset2 = tableOffset2 + tableStep2;
      tableOffset3 = tableOffset3 + tableStep3;
      tableOffset4 = tableOffset4 + tableStep4;
      waveValue1 = (waveTable[tableOffset1 >> 7]) >> 4;
      waveValue2 = (waveTable[tableOffset2 >> 7]) >> 4;
      waveValue3 = (waveTable[tableOffset3 >> 7]) >> 2;
      waveValue4 = (waveTable[tableOffset4 >> 7]) >> 1;
      summedValue = waveValue1 + waveValue2 + waveValue3 + waveValue4;
      PORTD = (((signed int)(summedValue * envelopeValue)) >> 8) + 0x80;
      if(noteTime==0) {
        preScale = 20;
        noteState = 3;
        }
      else {
        noteTime = noteTime - 1;
        }
      break;
    case 3:                           // decay
      tableOffset1 = tableOffset1 + tableStep1;
      tableOffset2 = tableOffset2 + tableStep2;
      tableOffset3 = tableOffset3 + tableStep3;
      tableOffset4 = tableOffset4 + tableStep4;
      waveValue1 = (waveTable[tableOffset1 >> 7]) >> 4;
      waveValue2 = (waveTable[tableOffset2 >> 7]) >> 4;
      waveValue3 = (waveTable[tableOffset3 >> 7]) >> 2;
      waveValue4 = (waveTable[tableOffset4 >> 7]) >> 1;
      summedValue = waveValue1 + waveValue2 + waveValue3 + waveValue4;
      PORTD = (((signed int)(summedValue * envelopeValue)) >> 8) + 0x80;
      preScale--;
      if(preScale==0) {
        preScale = 80;
        if(envelopeValue != 0) {
          envelopeValue--;
          }
        else {
          tableOffset1 = 0;
          tableOffset2 = 0;
          tableOffset3 = 0;
          tableOffset4 = 0;
          tableStep1 = 0;
          tableStep2 = 0;
          tableStep3 = 0;
          tableStep4 = 0;
//          noteTime = 0xc35;
//          noteTime = 0x2000;
          if (tuneNotes[i]==0)
            i=0;
          noteState = 0;
          }
        }
      break;
    }
         
  PORTB &= 0xFE; 
}
void loop() {
}

 

The notes for the tune are held in the tuneNotes[] array. There are four numbers for the partials and a number for note duration (the note duration part of it isn't very well worked out - this is an experiment rather than a project). Above the array I've included, as comments, a whole scale of notes - that makes it easy to assemble a tune just by copying and pasteing.

 

Demonstration

 

Here it is playing a familiar tune.

 

 

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

 

It's not too bad - the notes do have a metallic, tinkly quality to them, but they don't really resonate in quite the way that a bell or chime would and they feel like the beginning has been removed. With a real chime or bell there's a period of noise at the start, when the energy arrives from the hammer/clanger and before the resonances of the structure filter it to particular frequencies, which I'm not modelling. It's also the case that each partial would decay at different rates and go on for longer than mine do. That's all too much for a simple Arduino to handle - one for you people with more impressive and capable SBCs, I think.

 

[1] Fundamentals of Musical Acoustics. Arthur H. Benade.

  • Sign in to reply

Top Comments

  • jc2048
    jc2048 over 7 years ago in reply to balearicdynamics +3
    I have a Uno. I don't have a Mega. So I chose the Uno. Space isn't really an issue. These are the figures for the sketch in the blog above: Sketch uses 3,256 bytes (10%) of program storage space. Maximum…
  • genebren
    genebren over 7 years ago +2
    It does sound a little like bells, but way too tinny. Bells are more harmonically rich and complex. Maybe you could add small amounts of a lower harmonic to add some richness to the tones. Gene
  • shabaz
    shabaz over 7 years ago +2
    H Jon, Great work trailblazing how to use the Arduino in so many music related ways! What is also significant is that you found a public library with decent books : )
Parents
  • genebren
    genebren over 7 years ago

    It does sound a little like bells, but way too tinny. Bells are more harmonically rich and complex.  Maybe you could add small amounts of a lower harmonic to add some richness to the tones.

    Gene

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • jc2048
    jc2048 over 7 years ago in reply to genebren

    I did try it with the lowest partial in place but it wasn't a very nice sound so I settled on this one for the video.

     

    It was quite a confused sound. The fast attack (but without the strike tone) gave it a plucked quality (a bit like a metallic harpsichord or spinet) which was all wrong with the non-harmonic overtones.

     

    I suspect that if I were to build this into a small box it would sound more realistic with the 'Tinny Tinkle' technology.

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

    I did try it with the lowest partial in place but it wasn't a very nice sound so I settled on this one for the video.

     

    It was quite a confused sound. The fast attack (but without the strike tone) gave it a plucked quality (a bit like a metallic harpsichord or spinet) which was all wrong with the non-harmonic overtones.

     

    I suspect that if I were to build this into a small box it would sound more realistic with the 'Tinny Tinkle' technology.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
No Data
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 © 2025 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

  • X
  • Facebook
  • linkedin
  • YouTube