Tuesday, January 24, 2017

New tone music page!




Hello! Do you like tone music? Maybe I've something for you! I've just started a new blog page containing my collection of tone music for Arduino. The page is accessible here and from the main menu. You will find 24 items at present but the list is (slowly) growing.

Please have a look the following posts for the playing software and how the musics are encoded.

Enjoy!

Wednesday, December 24, 2014

Tone music: changing the Tempo of your melodies





Abstract
In our past programs for playing tone music on Arduino (see the basic program here and its advanced version here) are based on a fixed Tempo which is about 90 crotchets per minute. In this article we give a simple routine which allows to change the Tempo. We also provide some basic conversion constants for the main Tempos.

Hey all! While transcribing some music sheet (game music) I've seen that the tempo was somewhat strange and it wasn't due only to the deformation of my poor loudspeaker. Indeed, our past sketches for playing tone music on Arduino (see the basic program here and its advanced version here) are based on a fixed Tempo which is approx 90 crotchets per minute. This is the same for all other sketches that I could find on the web.
Therefore, here is a simple sketch function which changes the Tempo in your melody.

The sketch
The code below contain just one function. Call it with your own tempo value or choose one constant among those provided in the next section. The formula to compute the transformation takes into account the pause that we put between a note and the following which was useful to distinguish the notes (this was set to 130% of the note duration in our previous programs). Whenever the duration is not standard (in the case of an augmentation for example), a simple approximation formula is used.

Warning: some older version of melodies that you can find over the net use const int noteDurations[] as data type. Of course, you should change this into uint16_t noteDurations[] to be able to use the setTempo() routine.


#include "durations.h"

#define INTERNOTE_PAUSE 1.3

void setTempo(uint16_t durs[], uint16_t tempo, uint16_t istart, uint16_t iend) {
  register uint16_t i;
  uint16_t base;
  
  base = (uint16_t)(1000.0/((tempo/60.0)*(1+INTERNOTE_PAUSE)));
  
  for(i=istart; i<iend; i++) {
    switch(durs[i]) {
      case DUR_SEMIBREVE: 
        durs[i] = base << 2;
        break;
      case DUR_MINIM: 
        durs[i] = base << 1;
        break;
      case DUR_CROTCHET: 
        durs[i] = base;
        break;
      case DUR_QUAVER:
        durs[i] = base >> 1;
        break;
      case DUR_SEMIQUAVER:
        durs[i] = base >> 2;
        break;
      case DUR_DEMISEMIQUAVER:
        durs[i] = base >> 3;
        break;
      case DUR_HEMIDEMISEMIQUAVER:
        durs[i] = base >> 4;
        break;
      default:
        durs[i] = (uint16_t)(durs[i]/(DUR_CROTCHET*1.0)*base);
        break;      
    }
  }
}

The tempos
In most of the music sheets, the tempo is indicated a phrase or a word (usually in Italian) and the interpretation of such words/phrases is often a matter of taste or of long discussions. Along with the previous sketch, below you can find Tempos.h: my personal interpretation of most known tempos.


/*
 *  Tempos.h
 *
 *  This is part of PlayMelodyAdv projet
 *  A more advanced program for playing melodies on Arduino.
 *
 *
 *  Written by Enrico Formenti, 22 dec 2014
 *
 *  BSD license, check the License page on the blog for more information
 *  All this text must be included in any redistribution.
 *
 *  See macduino.blogspot.com for more details.
 */

#ifndef _Tempos_h
#define _Tempos_h

#define TEMPO_LARGHISSIMO 24
#define TEMPO_GRAVE 32
#define TEMPO_LENTISSIMO 40
#define TEMPO_LENTO 46
#define TEMPO_LARGO 50
#define TEMPO_ADAGISSIMO 52
#define TEMPO_LARGHETTO 56
#define TEMPO_LENTO 60
#define TEMPO_ADAGIO 70
#define TEMPO_ADAGIETTO 76
#define TEMPO_ANDANTE 88
#define TEMPO_MODERATO 100
#define TEMPO_ALLEGRETTO 116
#define TEMPO_ALLEGRO 130
#define TEMPO_VIVACE 140
#define TEMPO_VIVACISSIMO 152
#define TEMPO_ALLEGRISSIMO 160
#define TEMPO_ALLEGRO_VIVACE 160
#define TEMPO_PRESTO 170
#define TEMPO_PRESTISSIMO 188

#endif

See also
Tone music surprises!
Tone music: advanced playing software
Tone music: how to encode songs

Enjoy! Credits
The image opening this post comes from Wikipedia.com

Monday, December 22, 2014

Tone music: advanced playing software




Abstract
In this post we are going to present a more sophisticated program for playing melodies on your Arduino. It allows you to encode repetitions and alternate endings, compacting your longer melodies.
Keywords: tone music; pauses; augmentations; ties; repetitions.

The new playing routine
The new play function implements more sophisticated management of melodies allowing pauses, ties, augmentations (like the past routine) and it also introduces the possibility to use repetitions and alternate endings. This post explains how to encode all this.

The sketch with the new routine is given below. Remark that it makes use of a support class that implements a simple stack. Source files can found here: Stack.h, Stack.cpp. In order to be able to compile the sketch you should open this two files in other tabs of your Arduino IDE. You also need instructions.h which contains the encoding for the new instructions used to encode the melodies.

Compatibility
All the songs encoded for the previous version of the playing routine still work for this new version without any modification. Indeed, the new melody encoding is an extension of the older one.

See also
Tone music surprises!
Tone music: how to encode songs
Tone music: changing the Tempo of your melodies

Enjoy!

/*
 *  PlayMelodyAdv
 *
 *  A more advanced program for playing melodies on Arduino. 
 *
 *  Define the label DEBUG to have some debug support
 *
 *  Written by Enrico Formenti, 22 dec 2014
 *
 *  BSD license, check the License page on the blog for more information
 *  All this text must be included in any redistribution.
 *
 *  See macduino.blogspot.com for more details.
 */

#include "pitches.h"
#include "durations.h"
#include "instructions.h"
#include "Stack.h"
#include "Stack.cpp"
#include "SilentNight.h"
 
#define TONEPIN 8

typedef struct {
  struct {
  uint16_t N;  // position in melody array
  uint16_t D;  // position in durations array
  } I;         // individual addressing
  uint32_t A;  // addressing all together
} POS;

void playMusic( uint16_t *instr, uint16_t *durs, uint16_t len) {

  POS coda;      // address of coda symbol
  POS segno;     // address of segno symbol
  POS invRepeat; // position of inv repeat sign
  POS nskip;     // posistion of the first note to skip
  POS fine;      // end of music symbol position
  POS askip;     // position of the first note to skip in alternate ending
  POS curPos; 

  // reset all internal variables
  coda.A = 0;
  segno.A = 0;
  invRepeat.A = 0;
  nskip.A = 0;
  fine.A = 0;
  askip.A = 0;
  curPos.A = 0;
  
  // start looping
  while(curPos.I.N < len) {
    Stack<POS> reps; // make the stack local so it is emptied when the loop 
                     // is over

    switch(instr[curPos.I.N]) {
      case NOTE_PAUSE:
        // noTone(TONEPIN);
        delay(durs[curPos.I.D]);
        curPos.A += 0x11;
        break;
      case NOTE_CODA:
        if(nskip.A) {
          curPos.A = nskip.A;
          nskip.A = 0;
          coda.A = 0;
          break;
        }
        coda.A = curPos.A+0x10; // start from next position
        (curPos.I.N)++;
        break;
      case NOTE_DACAPO:
        if(reps.isEmpty() || (reps.topElement().A!=curPos.A)) { // if this event has not already occurred
          reps.push(curPos); // add this event
          curPos.A=0;  // repeat from the beginning
          break;
        }
        // otherwise we simply skip and update the instruction pointer
        reps.pop();
        (curPos.I.N)++;
        break;
      case NOTE_SEGNO:
        segno.A=curPos.A+0x10; // start from next position in note array
        (curPos.I.N)++;        
        break;
      case NOTE_REPEAT:
        if(reps.isEmpty() || (reps.topElement().A != curPos.A)) {
          if(invRepeat.A) { // repeat from last inv repeat sign if any
            curPos.A=invRepeat.A+0x11; // add +1 to both N and D pointers
            invRepeat.A=0;
            reps.push(curPos);// push the event on the stack
            break;
          }
          // otherwise repeat from the beginning
          reps.push(curPos);// push the event on the stack
          curPos.A=0;
          break;
        }
        // if this is the sign that issued the event
        reps.pop();
        (curPos.I.N)++;
        break;
      case NOTE_INVREPEAT:
        invRepeat.A=curPos.A+0x10; // start from the next position in notes array
        (curPos.I.N)++;
        break;
      case NOTE_DALSEGNO:
        if(reps.isEmpty() || (reps.topElement().A!=curPos.A)) { // if this has not generated the event
          reps.push(curPos);
          curPos.A=segno.A;
          segno.A=0;
          break;
        }
        // otherwise skip and update N only
        reps.pop();
        segno.A=0;
        (curPos.I.N)++;
        break;
      case NOTE_DALSEGNOCODA:
        if(reps.isEmpty() || (reps.topElement().A!=curPos.A)) {
          reps.push(curPos);
          curPos.A = segno.A;
          segno.A = 0;
          nskip.A = coda.A+0x10;
          break;
        }
        // otherwise skip and update N only
        reps.pop();
        (curPos.I.N)++;
        break;
        case NOTE_DACAPOCODA:
        if(reps.isEmpty() || (reps.topElement().A!=curPos.A)) {
          reps.push(curPos);
          curPos.A = 0;
          segno.A = 0;
          nskip.A = coda.A+0x10;
          break;
        }
        // otherwise skip and update N only
        reps.pop();
        (curPos.I.N)++;
        break;
      case NOTE_FINE:
        if(fine.A) { // we already passed through the music end symbol
          curPos.I.N = len; // then stop playing
          break;
        }
        fine.A = curPos.A;
        (curPos.I.N)++;
        break;
      case NOTE_DACAPOFINE:
        curPos.A = 0;
        break;
      case NOTE_DALSEGNOFINE:
        curPos.A = segno.A;
        break;
      case NOTE_ALTBEGIN:
        if(askip.A) { // we are repeating the sequence, hence skip
          curPos.A = askip.A;
          askip.A = 0;
          break;
        }
        // not repeating so just keep playing
        (curPos.I.N)++;
        break;
      case NOTE_ALTEND:
        askip.A = curPos.A+0x10; // set the skip to the next instruction
                                 // so that it will be skipped during the
                                 // repetition
        break;   
      default: // it is a note instruction
        tone(TONEPIN, instr[curPos.I.N], durs[curPos.I.D]);
        // to distinguish the notes, set a minimum time between them.
        // the note's duration + 30% seems to work well:
        delay(durs[curPos.I.D] * 1.3);
        // stop the tone playing:
        noTone(TONEPIN);
        curPos.A += 0x11; // update both N and D pointers
        break;
    }
  }
}

void setup() {
  
#ifdef DEBUG
  Serial.begin();
#endif
  
  playMusic((uint16_t *)melody,(uint16_t *)noteDurations,(uint16_t)melody_len);  
}

void loop() {
  // no need to repeat the melody.
}

Tone music: how to encode songs





Abstract
In this article we explain how to encode tone music for your Arduino projects. In particular, we explain how to encode pauses, ties, repetitions, etc. This new encoding extends the one we have proposed in a past post. The main advantage is that it can considerably shorten melodies physical description and hence save memory space.
Keywords: tone music; pauses; augmentations; ties; repetitions.

Which music sheets to use?
It is not clear which sheets translate better into tone music. I prefer to use easy piano music sheets, or simply start from scratch by trials and errors.

Basic encoding
Encoding a music sheet essentially consists in defining the following three objects:
uint16_t instr_len:this is the length of the array melody. Remark that the size of a melody is limited by the size of int. This is not a true limitation since this is far beyond the memory capabilities of Arduino Uno.
uint16_t instr[]:array containing the instructions for playing the melody
uint16_t durs[]:array containing the instructions for the duration of the current note or of the current pause.

Sunday, December 14, 2014

Tone music surprises






Hey all! It's almost Christmas and time for the traditional carols. I've found a 8Ω loudspeaker from an old PC and I went through a classic Arduino Sketch for beginners. I've optimized it a little bit. Moreover, I've translated into French/Italian the notes and introduced standardized length for durations and the possibility to add pauses.