kd5rxt-mark
Well-known member
BACKGROUND: I have continued to expand my TeensyMIDIPolySynth project & am very pleased with how it keeps progressing. The current version uses a T4.1 + Audio Adapter Board + RA8875 display. All controls (buttons & sliders) are managed from custom menus & screens generated on the RA8875. Unfortunately, I have come to realize that a high-pitched noise is injected into the audio stream if/when the RA8875 is touched for control modification by the operator, so my latest activity involves limiting the existing T4.1 strictly for driving the display & managing operator inputs. In an attempt to eliminate this noise, I will be adding another T4.1 strictly for generating the audio. My plan is to connect the two T4.1s serially. As a side benefit, by splitting the functionality across a pair of T4.1s, I can also reduce my RAM usage, for which I am constantly bumping against the top end - I've left as many of my code functions in FLASHMEM as I dare & I put as many variables as I could into RAM2 (those that don't require any specific startup initialization), but it is still a continual challenge to keep from exceeding available RAM.
CONDITIONS:
Arduino IDE Configuration (last built with Arduino 1.8.19 + Teensyduino 1.56):
Tools/Board: "Teensy 4.1"
Tools/USB Type: "Serial + MIDI"
Tools/CPU Speed: "600MHz"
Tools/Optimize: "Smallest Code"
Tools/Keyboard Layout: "US English"
Tools/Port: "COMx Serial+MIDI (Teensy 4.1)"
In order to investigate an apparent conflict between using Serial5 on the T4.1 while connected to a T4 Audio Adapter Board, I am running the following code (NOTE: this assumes that you have a T4.1 stacked directly on top of a T4 Audio Adapter Board using properly soldered mating headers, and that you have the volume pot installed on the Audio Adapter Board and/or you have a pot connected between 3.3VDC & GROUND, with the wiper connected to A1) to demonstrate how the basic capability is expected to operate (this code represents a bare-bones extract of my Teensy-MIDI-RA8875-PolySynth . . . just enough to reproduce the apparent problem). Using this simple example, the serial comms from the DISPLAY T4.1 to the AUDIO T4.1 can be observed in the Serial Monitor (showing a very simple example of the configuration data set by the operator using the menus & displays, which is then forwarded serially to the AUDIO T4.1 to configure & drive the Audio Adapter Board capabilities).
Because I've consumed a large number of the T4.1 pins already, I am relegated to using either Serial4 or Serial5 on the DISPLAY T4.1. Now, here's where things get weird: If "EAserial" is defined to be "Serial4", everything (with the exception of being able to monitor the data in the Serial Monitor, since it is no longer using Serial) works just like it did before (when using Serial). The audio is generated as expected by the Audio Adapter Board.
However, if "EAserial" is defined to be "Serial5", then no audio is generated by the Audio Adapter Board.
I did try adding varying amounts of delay before, between, & after the Serialx.begin() calls, but did not find any combinations that made any difference. I am content using Serial4, but am really curious why Serial5 does not also work ?!?!?
Mark J Culross
KD5RXT
CONDITIONS:
Arduino IDE Configuration (last built with Arduino 1.8.19 + Teensyduino 1.56):
Tools/Board: "Teensy 4.1"
Tools/USB Type: "Serial + MIDI"
Tools/CPU Speed: "600MHz"
Tools/Optimize: "Smallest Code"
Tools/Keyboard Layout: "US English"
Tools/Port: "COMx Serial+MIDI (Teensy 4.1)"
In order to investigate an apparent conflict between using Serial5 on the T4.1 while connected to a T4 Audio Adapter Board, I am running the following code (NOTE: this assumes that you have a T4.1 stacked directly on top of a T4 Audio Adapter Board using properly soldered mating headers, and that you have the volume pot installed on the Audio Adapter Board and/or you have a pot connected between 3.3VDC & GROUND, with the wiper connected to A1) to demonstrate how the basic capability is expected to operate (this code represents a bare-bones extract of my Teensy-MIDI-RA8875-PolySynth . . . just enough to reproduce the apparent problem). Using this simple example, the serial comms from the DISPLAY T4.1 to the AUDIO T4.1 can be observed in the Serial Monitor (showing a very simple example of the configuration data set by the operator using the menus & displays, which is then forwarded serially to the AUDIO T4.1 to configure & drive the Audio Adapter Board capabilities).
Code:
//
// Demonstration of Teensy Audio + Serial5 Conflict
//
// Pared down from Teensy 4.1 MIDI (12-note / 3-voice) RA8875-Controlled Polyphonic Synthesizer
//
// Arduino IDE Configuration (last built with Arduino 1.8.19 + Teensyduino 1.56):
// Tools/Board: "Teensy 4.1"
// Tools/USB Type: "Serial + MIDI"
// Tools/CPU Speed: "600MHz"
// Tools/Optimize: "Smallest Code"
// Tools/Keyboard Layout: "US English"
// Tools/Port: "COMx Serial+MIDI (Teensy 4.1)"
//
#include <SPI.h>
#include <Audio.h>
// GUItool: begin automatically generated code
AudioSynthWaveformModulated VFOsquare; //xy=129.5,120
AudioOutputI2S i2s1; //xy=309.5,120
AudioConnection patchCord1(VFOsquare, 0, i2s1, 0);
AudioConnection patchCord2(VFOsquare, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=129.5,60
// GUItool: end automatically generated code
#define EAserial Serial
// MIDI note-to-frequency data from: http://tonalsoft.com/pub/news/pitch-bend.aspx
#define FLOAT_NOTE_OFF 0.000
#define FLOAT_NOTE_END 99999.999
#define FLOAT_NOTE_C0 16.352
#define FLOAT_NOTE_CS0 17.324
#define FLOAT_NOTE_D0 18.354
#define FLOAT_NOTE_DS0 19.445
#define FLOAT_NOTE_E0 20.602
#define FLOAT_NOTE_F0 21.827
#define FLOAT_NOTE_FS0 23.125
#define FLOAT_NOTE_G0 24.500
#define FLOAT_NOTE_GS0 25.957
#define FLOAT_NOTE_A0 27.500
#define FLOAT_NOTE_AS0 29.135
#define FLOAT_NOTE_B0 30.868
#define FLOAT_NOTE_C1 32.703
#define FLOAT_NOTE_CS1 34.648
#define FLOAT_NOTE_D1 36.708
#define FLOAT_NOTE_DS1 38.891
#define FLOAT_NOTE_E1 41.203
#define FLOAT_NOTE_F1 43.654
#define FLOAT_NOTE_FS1 46.249
#define FLOAT_NOTE_G1 48.999
#define FLOAT_NOTE_GS1 51.913
#define FLOAT_NOTE_A1 55.000
#define FLOAT_NOTE_AS1 58.270
#define FLOAT_NOTE_B1 61.735
#define FLOAT_NOTE_C2 65.406
#define FLOAT_NOTE_CS2 69.296
#define FLOAT_NOTE_D2 73.416
#define FLOAT_NOTE_DS2 77.782
#define FLOAT_NOTE_E2 82.407
#define FLOAT_NOTE_F2 87.307
#define FLOAT_NOTE_FS2 92.499
#define FLOAT_NOTE_G2 97.999
#define FLOAT_NOTE_GS2 103.826
#define FLOAT_NOTE_A2 110.000
#define FLOAT_NOTE_AS2 116.541
#define FLOAT_NOTE_B2 123.471
#define FLOAT_NOTE_C3 130.813
#define FLOAT_NOTE_CS3 138.591
#define FLOAT_NOTE_D3 146.832
#define FLOAT_NOTE_DS3 155.563
#define FLOAT_NOTE_E3 164.814
#define FLOAT_NOTE_F3 174.614
#define FLOAT_NOTE_FS3 184.997
#define FLOAT_NOTE_G3 195.998
#define FLOAT_NOTE_GS3 207.652
#define FLOAT_NOTE_A3 220.000
#define FLOAT_NOTE_AS3 233.082
#define FLOAT_NOTE_B3 246.942
#define FLOAT_NOTE_C4 261.626
#define FLOAT_NOTE_CS4 277.183
#define FLOAT_NOTE_D4 293.665
#define FLOAT_NOTE_DS4 311.127
#define FLOAT_NOTE_E4 329.628
#define FLOAT_NOTE_F4 349.228
#define FLOAT_NOTE_FS4 369.994
#define FLOAT_NOTE_G4 391.995
#define FLOAT_NOTE_GS4 415.305
#define FLOAT_NOTE_A4 440.000
#define FLOAT_NOTE_AS4 466.164
#define FLOAT_NOTE_B4 493.883
#define FLOAT_NOTE_C5 523.251
#define FLOAT_NOTE_CS5 554.365
#define FLOAT_NOTE_D5 587.330
#define FLOAT_NOTE_DS5 622.254
#define FLOAT_NOTE_E5 659.255
#define FLOAT_NOTE_F5 698.456
#define FLOAT_NOTE_FS5 739.989
#define FLOAT_NOTE_G5 783.991
#define FLOAT_NOTE_GS5 830.609
#define FLOAT_NOTE_A5 880.000
#define FLOAT_NOTE_AS5 932.328
#define FLOAT_NOTE_B5 987.767
#define FLOAT_NOTE_C6 1046.502
#define FLOAT_NOTE_CS6 1108.731
#define FLOAT_NOTE_D6 1174.659
#define FLOAT_NOTE_DS6 1244.508
#define FLOAT_NOTE_E6 1318.510
#define FLOAT_NOTE_F6 1396.913
#define FLOAT_NOTE_FS6 1479.978
#define FLOAT_NOTE_G6 1567.982
#define FLOAT_NOTE_GS6 1661.219
#define FLOAT_NOTE_A6 1760.000
#define FLOAT_NOTE_AS6 1864.655
#define FLOAT_NOTE_B6 1975.533
#define FLOAT_NOTE_C7 2093.005
#define FLOAT_NOTE_CS7 2217.461
#define FLOAT_NOTE_D7 2349.318
#define FLOAT_NOTE_DS7 2489.016
#define FLOAT_NOTE_E7 2637.020
#define FLOAT_NOTE_F7 2793.826
#define FLOAT_NOTE_FS7 2959.955
#define FLOAT_NOTE_G7 3135.963
#define FLOAT_NOTE_GS7 3322.438
#define FLOAT_NOTE_A7 3520.000
#define FLOAT_NOTE_AS7 3729.310
#define FLOAT_NOTE_B7 3951.066
#define FLOAT_NOTE_C8 4186.009
#define FLOAT_NOTE_CS8 4434.922
#define FLOAT_NOTE_D8 4698.636
#define FLOAT_NOTE_DS8 4978.032
#define FLOAT_NOTE_E8 5274.041
#define FLOAT_NOTE_F8 5587.651
#define FLOAT_NOTE_FS8 5919.911
#define FLOAT_NOTE_G8 6271.927
#define FLOAT_NOTE_GS8 6644.875
#define FLOAT_NOTE_A8 7040.000
#define FLOAT_NOTE_AS8 7458.620
#define FLOAT_NOTE_B8 7902.133
#define FLOAT_NOTE_C9 8372.018
#define FLOAT_NOTE_CS9 8869.844
#define FLOAT_NOTE_D9 9397.273
#define FLOAT_NOTE_DS9 9956.063
#define FLOAT_NOTE_E9 10548.082
#define FLOAT_NOTE_F9 11175.303
#define FLOAT_NOTE_FS9 11839.822
#define FLOAT_NOTE_G9 12543.854
#define FLOAT_NOTE_GS9 13289.750
#define FLOAT_NOTE_A9 14080.000
#define FLOAT_NOTE_AS9 14917.240
#define FLOAT_NOTE_B9 15804.266
#define FLOAT_NOTE_C10 16744.036
typedef enum
{
EA_INDEX_MAIN_LINE_VOLUME_SLIDER = 0,
EA_INDEX_MAIN_PHONES_VOLUME_SLIDER,
} EA_INDEX;
struct NOTE_ENTRY
{
float noteValue;
int durationInMillis;
};
#define TOTAL_NOTE_ENTRIES 12
NOTE_ENTRY notes[TOTAL_NOTE_ENTRIES] =
{ {FLOAT_NOTE_C4, 50}, {FLOAT_NOTE_OFF, 100},
{FLOAT_NOTE_DS4, 50}, {FLOAT_NOTE_OFF, 100},
{FLOAT_NOTE_FS4, 50}, {FLOAT_NOTE_OFF, 100},
{FLOAT_NOTE_A4, 50}, {FLOAT_NOTE_OFF, 100},
{FLOAT_NOTE_C5, 50}, {FLOAT_NOTE_OFF, 100},
{FLOAT_NOTE_C3, 250},
{FLOAT_NOTE_OFF, 1000},
};
int runningAvgVolumePotValue = analogRead(A1);
#define VOLUME_POT_SAMPLE_MILLIS 250
unsigned long targetMillis = millis();
unsigned long nextVolumeSampleMillis = millis() + VOLUME_POT_SAMPLE_MILLIS;
int noteIndex = -1;
// main loop
void loop()
{
int newVolumePotValue = analogRead(A1);
if (millis() > nextVolumeSampleMillis)
{
nextVolumeSampleMillis += VOLUME_POT_SAMPLE_MILLIS;
if (runningAvgVolumePotValue != (int)((((float)runningAvgVolumePotValue * 2.0) + (float)newVolumePotValue) / 3.0))
{
runningAvgVolumePotValue = (int)((((float)runningAvgVolumePotValue * 2.0) + (float)newVolumePotValue) / 3.0);
sgtl5000_1.lineOutLevel(map(runningAvgVolumePotValue, 0, 1023, 0, 15));
sgtl5000_1.volume(0.8 * ((float)runningAvgVolumePotValue / 1024.0));
sendEAsliderValue(EA_INDEX_MAIN_PHONES_VOLUME_SLIDER, runningAvgVolumePotValue);
sendEAsliderValue(EA_INDEX_MAIN_LINE_VOLUME_SLIDER, map(runningAvgVolumePotValue, 0, 1023, 0, 15));
}
}
// if it's time to play the next note
if (millis() >= targetMillis)
{
if (++noteIndex > (TOTAL_NOTE_ENTRIES - 1))
{
noteIndex = 0;
}
targetMillis = millis() + notes[noteIndex].durationInMillis;
if (notes[noteIndex].noteValue != FLOAT_NOTE_END)
{
if (notes[noteIndex].noteValue == FLOAT_NOTE_OFF)
{
VFOsquare.amplitude(0.0);
} else {
VFOsquare.frequency(notes[noteIndex].noteValue);
VFOsquare.amplitude(1.0);
}
} else {
VFOsquare.amplitude(0.0);
}
}
} // loop()
// send an external audio (EA) slider value
void sendEAsliderValue(EA_INDEX index, float value)
{
float localValue = ((float)((int)(value * 100))) / 100.00;
EAserial.print("EAs:0x");
// send the first digit of the index (in hex)
if ((index / 256) <= 9)
{
EAserial.print((char)((index / 256) + '0'));
} else {
EAserial.print((char)((index / 256) + 'A' - 10));
}
// send the second digit of the index (in hex)
if (((index / 16) % 16) <= 9)
{
EAserial.print((char)(((index / 16) % 16) + '0'));
} else {
EAserial.print((char)(((index / 16) % 16) + 'A' - 10));
}
// send the third digit of the index (in hex)
if ((index % 16) <= 9)
{
EAserial.print((char)((index % 16) + '0'));
} else {
EAserial.print((char)((index % 16) + 'A' - 10));
}
EAserial.print(":");
if (value >= 0.00)
{
EAserial.print("+");
} else {
EAserial.print("-");
}
localValue = abs(localValue);
EAserial.print((char)((int)(localValue / 10000) + '0'));
EAserial.print((char)(((int)(localValue / 1000) % 10) + '0'));
EAserial.print((char)(((int)(localValue / 100) % 10) + '0'));
EAserial.print((char)(((int)(localValue / 10) % 10) + '0'));
EAserial.print((char)(((int)localValue % 10) + '0'));
EAserial.print(".");
EAserial.print((char)(((int)(localValue * 10) % 10) + '0'));
EAserial.print((char)(((int)(localValue * 100) % 10) + '0'));
EAserial.println(";");
} // sendEAsliderValue()
// one-time setup
void setup()
{
Serial.begin(57600);
while (!Serial && (millis() <= 1000));
EAserial.begin(115200);
while (!EAserial && (millis() <= 1000));
AudioMemory(128);
sgtl5000_1.enable();
} // setup()
// EOF placeholder
Because I've consumed a large number of the T4.1 pins already, I am relegated to using either Serial4 or Serial5 on the DISPLAY T4.1. Now, here's where things get weird: If "EAserial" is defined to be "Serial4", everything (with the exception of being able to monitor the data in the Serial Monitor, since it is no longer using Serial) works just like it did before (when using Serial). The audio is generated as expected by the Audio Adapter Board.
Code:
#define EAserial Serial4 // works just fine with the Audio Adapter Board
However, if "EAserial" is defined to be "Serial5", then no audio is generated by the Audio Adapter Board.
Code:
#define EAserial Serial5 // conflicts with the Audio Adapter Board
I did try adding varying amounts of delay before, between, & after the Serialx.begin() calls, but did not find any combinations that made any difference. I am content using Serial4, but am really curious why Serial5 does not also work ?!?!?
Mark J Culross
KD5RXT