3 part harmony?

188 views
Skip to first unread message

mark lafond

unread,
Apr 13, 2015, 9:14:42 PM4/13/15
to mozzi...@googlegroups.com
Hello,
New to synth, new to mozzi, new to arduino.  Yeah, noobie!
I'm a model railroader interested in creating diesel train horn sound, harmonizing 3 notes: 493.88622.25, and 880.00 Hz, with my arduino triggered with a momentary push button. 
While I'm at it, I could use a bell that repeats as long as the button is held down.
Last, I'm hoping I'lll still be able to use the arduino for other layout functions (i.e. crossing gates)
I could use any help. Thanks!


Mr Sensorium

unread,
Apr 15, 2015, 12:46:19 AM4/15/15
to mozzi...@googlegroups.com
Hi Mark,
once you have the library installed, there are some examples you can base your sketch on.  Here is Examples>Mozzi>01.Basics>Sinewave modified to play 3 tones at the frequencies you listed.  You could use an envelope to shape the amplitude of the sound(s), like in Examples>Mozzi>07.Envelopes>ADSR_Audio_Rate_Envelope, or ADSR_Audio_Rate_Envelope_x2, which shows how to envelope  and sum two sources.  An example showing how to use a button to change audio is attached.

#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/sin2048_int8.h> // sine table for oscillator

// use: Oscil <table_size, update_rate> oscilName (wavetable), look in .h file of table #included above
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin1(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin3(SIN2048_DATA);

void setup(){
  startMozzi
(CONTROL_RATE); // set a control rate of 64 (powers of 2 please)
  aSin1
.setFreq(493.88f); // set the frequency
  aSin2
.setFreq(622.25f);
  aSin3
.setFreq(880.00f);
}


void updateControl(){
 
// put changing controls in here
}


int updateAudio(){
 
return  ((int)aSin1.next() + aSin2.next() + aSin3.next())>>1;
}


void loop(){
  audioHook
(); // required here
}


The example 08.Samples>Sample plays a sample repeatedly using a timer, or you can play a sample looping without needing to retrigger it with a timer by using setLoopingOn().  The docs for Sample are here: https://sensorium.github.io/Mozzi/doc/html/class_sample.html#a40e76011d841b84d2d54bf2cec6c4d5f

You could probably fit some more things into a sketch, though space for samples is a consideration..
Also, if you are new to Arduino and Mozzi, the Arduino examples are useful tutorials, and there is this tute for Mozzi...https://sensorium.github.io/Mozzi/learn/

Good luck
Tim
Sinewave_Button.ino

mark lafond

unread,
Apr 15, 2015, 6:54:29 PM4/15/15
to mozzi...@googlegroups.com
Thanks, Mr. Senorium!  You've given me a bunch to check out.  I'll get back to you.

mark lafond

unread,
Apr 24, 2015, 10:01:29 PM4/24/15
to mozzi...@googlegroups.com
Well I've certainly learned a lot, but I need your help!  The following does sound 3 notes simultaneously for the duration of a button push.  I can't get the ASDR envelope to work, even though it works in a separate program that sounds one note repeatedly, without button control, in other words, the lines of code that should affect the notes have no effect:


#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/chum78_int8.h> // sine table for oscillator
#include <EventDelay.h>
#include <ADSR.h>

// use: Oscil <table_size, update_rate> oscilName (wavetable), look in .h file of table #included above
Oscil <CHUM78_NUM_CELLS, AUDIO_RATE> aSin1(CHUM78_DATA);
Oscil <CHUM78_NUM_CELLS, AUDIO_RATE> aSin2(CHUM78_DATA);
Oscil <CHUM78_NUM_CELLS, AUDIO_RATE> aSin3(CHUM78_DATA);
Oscil <8192, AUDIO_RATE> aOscil(CHUM78_DATA);;
// set pin numbers:
const int buttonPin = 4;     // the number of the pushbutton pin
int buttonState = 0;         // variable for reading the pushbutton status\

// use #define for CONTROL_RATE, not a constant
#define CONTROL_RATE 64 // powers of 2 please

// for triggering the envelope
EventDelay noteDelay;
ADSR <CONTROL_RATE, CONTROL_RATE> envelope;
byte gain;

void setup(){
  startMozzi(CONTROL_RATE); // set a control rate of 64 (powers of 2 please)
}

unsigned int duration, attack, decay, sustain, release_ms;

void updateControl(){
  // put changing controls in here
    // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

if(noteDelay.ready()){
      // choose envelope levels. Necessary but overwritten below
      byte attack_level = 1000;
      byte decay_level = 1000;
      envelope.setADLevels(attack_level,decay_level);  
    {  
 // Set the ASDR Levels
       attack = 250;
       decay = 500;
       sustain = 1000;
       release_ms = 500;
     }
     envelope.setTimes(attack,decay,sustain,release_ms);    
     envelope.noteOn();
     noteDelay.start(attack+decay+sustain+release_ms);
   } 
   
  envelope.update();
  gain = envelope.next(); // this is where it's different to an audio rate envelope     
  aOscil.setFreq(500);
  
{ if (buttonState == HIGH) {     
  aSin1.setFreq(600); // set the frequency
  aSin2.setFreq(880);
  aSin3.setFreq(1200); 
}
else {
  aSin1.setFreq(0); // set the frequency
//  aSin2.setFreq(0);
//  aSin3.setFreq(0);
}
}
}

int updateAudio(){
 return  ((int)aSin1.next() + aSin2.next() + aSin3.next())>>1;
 return (int) (gain * aOscil.next())>>8;
}

void loop(){
  audioHook(); // required here
}


Mr Sensorium

unread,
Apr 25, 2015, 5:14:54 AM4/25/15
to mozzi...@googlegroups.com
Hi Mark,
this works for me (I changed the waveform to square - not sure the most appropriate for modelling a train whistle ... or would it be an electronic signal anyway?):
#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/smoothsquare8192_int8.h> // squarewave table for oscillator
#include <ADSR.h>


const int buttonPin = 4;     // the number of the pushbutton pin

Oscil <SMOOTHSQUARE8192_NUM_CELLS, AUDIO_RATE> aSig1(SMOOTHSQUARE8192_DATA);
Oscil <SMOOTHSQUARE8192_NUM_CELLS, AUDIO_RATE> aSig2(SMOOTHSQUARE8192_DATA);
Oscil <SMOOTHSQUARE8192_NUM_CELLS, AUDIO_RATE> aSig3(SMOOTHSQUARE8192_DATA);

ADSR
<CONTROL_RATE, AUDIO_RATE> envelope;


void setup() {
  startMozzi
();
  envelope
.setADLevels(255,255);
  envelope
.setTimes(250,500,1000,500); // will release after 1750 ms or earlier if button is released sooner
  aSig1
.setFreq(600); // set the frequency
  aSig2
.setFreq(880);
  aSig3
.setFreq(1200);
}

boolean triggered = false;

void updateControl() {
 
if (digitalRead(buttonPin) == HIGH) {
   
if (!triggered){ // only happens once at start of each button press
      envelope
.noteOn();
      triggered
= true;
   
}
 
}
 
else { // button off
    envelope
.noteOff();
    triggered
= false;
 
}
  envelope
.update();
}


int updateAudio(){
 
int whistle = ((int)aSig1.next() + aSig2.next() + aSig3.next())>>1;
 
return ((long)envelope.next() * whistle)>>8;

mark lafond

unread,
Apr 25, 2015, 9:17:42 AM4/25/15
to mozzi...@googlegroups.com
AWESOME!!  THANKS!!


On Monday, April 13, 2015 at 9:14:42 PM UTC-4, mark lafond wrote:
Reply all
Reply to author
Forward
0 new messages