Closed dwjbosman closed 4 years ago
Try using CHA
instead of CHB
Using CHA I'm getting garbled/corrupted sound.
I only need one servo. Should I use specific pin combinations for the servo and the sound output?
I looked at the source code. The servo library uses Timer1.
Your library allows to set USE_TIMER1. I did not acctivate this setting. I see that the library then uses timer 2. However
In SynthEngine.cpp:
# if defined(USE_TIMER1)
SIGNAL(TIMER2_COMPB_vect)
# else
SIGNAL(TIMER1_COMPB_vect)
# endif
Shouldn't this be the other way around?
Also in synthEngine::begin you are setting timer 1 irrespective of USE_TIMER1. This will conflict with the Servo library. I have tried to do a quick update. Unfortunately it's not working.
void synthEngine::begin(unsigned char voice, unsigned char d)
{
numVoice++;
#if defined(__AVR_ATmega32U4__)||defined(ESP8266)
begin(voice);
#else
# if defined(__AVR__)
cli();
# if defined(__AVR_ATmega2560__)
TCCR4A = 0x00; //-Start audio interrupt
TCCR4B = 0x09;
OCR4A=16000000.0 / FS_music; //-Auto sample rate
SET(TIMSK4, OCIE4B); //-Start audio interrupt
# else
//mTCCR1A = 0x00; //-Start audio interrupt
mTCCR2A = 0x00; <-------changed
# if defined(USE_TIMER1)
mTCCR1B = (1 << CS21);
# else
// mTCCR1B = 0x09;
mTCCR2B = 0x09; <-------changed
# endif
//mOCR1A=16000000.0 / FS_music; //-Auto sample rate
mOCR2A=16000000.0 / FS_music; <-------changed
//SET(mTIMSK1, mOCIE1B); //-Start audio interrupt
SET(mTIMSK2, mOCIE2B); <-------changed
# endif
I believe even if the servo were to work, the audio quality on the Arduino will be affected. I think a Teensy board or an ESP32 is a much better upgrade. The atmega328 has only 3 timers, of which 2 can be used because timer 0 is millis(). Timer 1 is a 16-bit timer, and timer 2 is an 8-bit timer. By default, the library uses Timer 2. The problem is that the servo timer is interfering with the high-frequency PWM of timer 2. I'm not sure how to solve it at the moment. http://www.righto.com/2009/07/secrets-of-arduino-pwm.html
I'm running this on a teensy 3.2 and it works without a sweat:
#include <NoodleSynth.h>
#include <Servo.h>
synthEngine mixer(20E3);
const char song[] PROGMEM = "::e,8f,8g,8a,8b,8c1,8d1,8e1"; //the C major scale. This format is known as RingTone Transfer Language or RTTL(It was used by Nokia's phone company).
const char song2[] PROGMEM = ":d=4:c,d,e,f";
const char song3[] PROGMEM = ":o=6,d=2:16a,16b,8a,4b";
const char song4[] PROGMEM = ":o=5,d=2:32g,32a,32b,32c";
MusicWithoutDelay instrument(song); //d=4 means that every note without a number in front of the letter is assumed to be a quarter note.
MusicWithoutDelay instrument2(song2);
MusicWithoutDelay instrument3(song3);
MusicWithoutDelay instrument4(song4);
Servo myservo; // create servo object to control a servo
int pos = 0; // variable to store the servo position
void setup() { //For details on the RTTL format, look at https://github.com/nathanRamaNoodles/MusicWithoutDelay-LIbrary documentation
// put your setup code here, to run once:
myservo.attach(9); // attaches the servo on pin 9 to the servo object
instrument.begin(CHB, TRIANGLE, ENVELOPE0, 0);
instrument2.begin(TRIANGLE, ENVELOPE0, 0);
instrument3.begin(TRIANGLE, ENVELOPE0, 0);
instrument4.begin(TRIANGLE, ENVELOPE0, 0);
Serial.begin(115200);
unsigned long t = instrument.getTotalTime(); //spits out total time in milliseconds
Serial.println(F("Type '1','2','3', or '4' to mute the corresponding instrument."));
Serial.print("Total Time: "); Serial.println(t / 1E3);
}
uint32_t pMillis = 0;
void loop() {
// put your main code here, to run repeatedly:
uint32_t cMillis = millis();
if (cMillis - pMillis > 250) {
myservo.write(pos % 180);
pos+=5;
pMillis = cMillis;
}
instrument.update(); //but its important to recognize that this library depends
instrument2.update();
instrument3.update();
instrument4.update();
if (instrument.isEnd()) { //on your main code not having delay(). Also, it increases stability, so your welcome :D
// instrument.pause(); //pauses song
// instrument2.pause();
// instrument3.pause();
// instrument4.pause();
}
if (Serial.available()) {
char str = Serial.read();
switch (str) {
case 's': //type 's' in Serial monitor.
//instrument.skipTo(instrument.getTotalTime() * (0.50)); //skip to halfway point
Serial.println("What's it to ya? I don't use delay, and you shouldn't either.\n Star this project on Github, and spread this good news to others.");
break;
case '1': //type 's' in Serial monitor.
instrument.mute(!instrument.isMuted());
break;
case '2': //type 's' in Serial monitor.
instrument2.mute(!instrument2.isMuted());
break;
case '3': //type 's' in Serial monitor.
instrument3.mute(!instrument3.isMuted());
break;
case '4': //type 's' in Serial monitor.
instrument4.mute(!instrument4.isMuted());
break;
}
}
}
Ok, I'll try it using a teensy 3.2
On the teensy 3.2 it works fine.
One last question. On the Uno I noticed that the speaker (which I have connected to a PAM8403 amplifier) becomes luke warm, while on the Teensy it becomes really hot. Any idea why?
I added a call to "analogWriteFrequency(A6, 375000);" to the setup function. The sound output is now much cleaner and the speaker doesn't run hot anymore.
If I try to use both Servo 1.1.7 and NoodleSynth 4.0.0 in one sketch on Arduino Uno it seems that only one of the libraries will work:
or
In the documentation you describe having solved the incompatibility. Should I do anything special?