Cant compile code based on audioshield example

Status
Not open for further replies.

massahwahl

Active member
I am using a modified version of Paul's example code for recording and playing back audio using teensy 4.0 and audio shield. Everything looks good except I am getting errors on all of the subroutine calls based on what the button does:

if (buttonRecord.fallingEdge()) {
Serial.println("Record Button Press");
if (mode == 2) stopPlaying();
if (mode == 0) startRecording();
}

Error: "message": "'stopPlaying' was not declared in this scope"

I am using PlatformIO in vsCode if that makes a difference.

Full code:

Code:
 #include <Arduino.h>
#include <korg_syro_volcasample.h>
// Three pushbuttons need to be connected:
//   Record Button: pin 0 to GND
//   Stop Button:   pin 1 to GND
//   Play Button:   pin 2 to GND
//   Syro Button:   pin 3 to GND
// This example code is in the public domain.

#include <SPI.h>
#include <SD.h>
#include <SD_t3.h>
#include <SerialFlash.h>

#include <Audio.h>
#include <Bounce.h>
#include <Wire.h>

//write wav
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate*numChannels*(bitsPerSample/8);// samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels*bitsPerSample/8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;

// which input on the audio shield will be used?
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;

AudioPlaySdWav           audioSD;
AudioInputI2S            audioInput;
AudioOutputI2S           audioOutput;
AudioRecordQueue         queue1;

//recod from mic
AudioConnection          patchCord1(audioInput, 0, queue1, 0);
AudioConnection          patchCord2(audioSD, 0, audioOutput, 0);
AudioConnection          patchCord3(audioSD, 0, audioOutput, 1);

AudioControlSGTL5000     audioShield;

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14
 
// Remember which mode we're doing
int mode = 0;  // 0=stopped, 1=recording, 2=playing
elapsedMillis  msecs;

// Bounce objects to easily and reliably read the buttons
Bounce buttonRecord = Bounce(0, 8);
Bounce buttonStop =   Bounce(1, 8);  // 8 = 8 ms debounce time
Bounce buttonPlay =   Bounce(2, 8);
Bounce buttonSyro =   Bounce(3, 8);

//////Korg Required Variables/////////////
uint8_t *pData; // pointer which specifies the data to be converted.
uint32_t Number; // the sample (0-99) or sequence pattern (0-9) number.
uint32_t Size; // size of data to be converted (in bytes).
              // set it to sizeof(VolcaSample_Pattern_Data) when converting sequence data.
uint32_t Quality; // The conversion bit depth. It can be set to 8-16. **By default this is set to 16.
Endian SampleEndian; //set to LittleEndian or BigEndian to suite your sample data.
int NumOfData; //The number of files we are sending to be converted by the syro converter process. When not specified, this is set to 1 by default.
uint32_t Flags; //This is always set to 0
uint32_t *pNumOfSyroFrame; // the pointer of the value which stores the size of the SyroData after conversion. Units in frames (an LR pair is one unit)

/////References for Syro Stuff/////
SyroDataType DataType;
//specifies any of the following data type to be converted.  
//DataType_Sample_Compress        //: convert single audio sample  
//DataType_Sample_Erase           //: delete single sample slot on volca sample  
//DataType_Sample_AllCompress     //: convert all sample data  
//DataType_Pattern       


// The file where data is recorded
File frec; 

void setup() {
///Korg Syro variables setup
// Quality = 16;
// Size = 512;
// SampleEndian = BigEndian;
// DataType = DataType_Sample_Compress;
// NumOfData = 1; //for testing, this is being set to 1
// Number = 1;

  // Configure the pushbutton pins
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);

  // Audio connections require memory, and the record queue
  // uses this memory to buffer incoming audio.
  AudioMemory(60);

  // Enable the audio shield, select input, and enable output
  audioShield.enable();
  audioShield.inputSelect(myInput);
  //audioShield.micGain(40);  //0-63
  audioShield.volume(0.5);  //0-1

  // Initialize the SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here if no SD card, but print a message
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
}

void loop() {
  // First, read the buttons
  buttonRecord.update();
  buttonStop.update();
  buttonPlay.update();
  buttonSyro.update();

  // Respond to button presses
  if (buttonRecord.fallingEdge()) {
    Serial.println("Record Button Press");
    if (mode == 2) stopPlaying();
    if (mode == 0) startRecording();
  }
  if (buttonStop.fallingEdge()) {
    Serial.println("Stop Button Press");
    if (mode == 1) stopRecording();
    if (mode == 2) stopPlaying();
  }
  if (buttonPlay.fallingEdge()) {
    Serial.println("Play Button Press");
    if (mode == 1) stopRecording();
    if (mode == 0) startPlaying();
  }
  if (buttonSyro.fallingEdge()) {
    Serial.println("Syro Button Press");
    if (mode == 1) stopRecording();
    if (mode == 0) SyroStatus SyroVolcaSample_Start(
                   SyroHandle *pHandle, 
                   SyroData *pData, 
                   int NumOfData,
                   uint32_t Flags,
                   uint32_t *pNumOfSyroFrame
                                             );
  }
  // If we're playing or recording, carry on...
  if (mode == 1) {
    continueRecording();
  }
  if (mode == 2) {
    continuePlaying();
  }

  // when using a microphone, continuously adjust gain
 //  if (myInput == AUDIO_INPUT_MIC) adjustMicLevel();
}

void startRecording() {
  Serial.println("startRecording");
  if (SD.exists("RECORD.WAV")) {
    SD.remove("RECORD.WAV");
  }
  frec = SD.open("RECORD.WAV", FILE_WRITE);
  if (frec) {
    queue1.begin();
    mode = 1;
    recByteSaved = 0L;
  }
}

void continueRecording() {
  
  if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer + 256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    // write all 512 bytes to the SD card
    frec.write(buffer, 512);
    recByteSaved += 512;
//    elapsedMicros usec = 0;
//    Serial.print("SD write, us=");
//    Serial.println(usec);
  }
}

void stopRecording() {
  Serial.println("stopRecording");
  queue1.end();
  if (mode == 1) {
    while (queue1.available() > 0) {
      frec.write((byte*)queue1.readBuffer(), 256);
      queue1.freeBuffer();
      recByteSaved += 256;
    }
    writeOutHeader();
    frec.close();
  }
  mode = 0;
}

void startPlaying() {
  Serial.println("startPlaying");
  audioSD.play("RECORD.WAV");
  mode = 2;

}

void stopPlaying() {
  Serial.println("stopPlaying");
  if (mode == 2) audioSD.stop();
  mode = 0;
}


void writeOutHeader() { // update WAV header with final filesize/datasize

//  NumSamples = (recByteSaved*8)/bitsPerSample/numChannels;
//  Subchunk2Size = NumSamples*numChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
  Subchunk2Size = recByteSaved;
  ChunkSize = Subchunk2Size + 36;
  frec.seek(0);
  frec.write("RIFF");
  byte1 = ChunkSize & 0xff;
  byte2 = (ChunkSize >> 8) & 0xff;
  byte3 = (ChunkSize >> 16) & 0xff;
  byte4 = (ChunkSize >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.write("WAVE");
  frec.write("fmt ");
  byte1 = Subchunk1Size & 0xff;
  byte2 = (Subchunk1Size >> 8) & 0xff;
  byte3 = (Subchunk1Size >> 16) & 0xff;
  byte4 = (Subchunk1Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = AudioFormat & 0xff;
  byte2 = (AudioFormat >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = numChannels & 0xff;
  byte2 = (numChannels >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = sampleRate & 0xff;
  byte2 = (sampleRate >> 8) & 0xff;
  byte3 = (sampleRate >> 16) & 0xff;
  byte4 = (sampleRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = byteRate & 0xff;
  byte2 = (byteRate >> 8) & 0xff;
  byte3 = (byteRate >> 16) & 0xff;
  byte4 = (byteRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = blockAlign & 0xff;
  byte2 = (blockAlign >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = bitsPerSample & 0xff;
  byte2 = (bitsPerSample >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  frec.write("data");
  byte1 = Subchunk2Size & 0xff;
  byte2 = (Subchunk2Size >> 8) & 0xff;
  byte3 = (Subchunk2Size >> 16) & 0xff;
  byte4 = (Subchunk2Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.close();
  Serial.println("header written"); 
  Serial.print("Subchunk2: "); 
  Serial.println(Subchunk2Size); 
}
 
Last edited:
I don't get that error message. What I get is that continuePlaying is undefined. In the original example code, continuePlaying is defined between startPlaying and stopPlaying but in your code it isn't there. I suspect that what happened was that you didn't need that function and removed it from the sketch but didn't remove the code that called it. The code compiles when that call is commented.

+edit Just seen Paul's reply. Looks like there is a difference between PlatformIO and Arduino IDE (which I used)
Pete
 
Yes, it probably does make a difference. Can you give it a try in Arduino, just to confirm whether the problem is the code itself or a difference between Arduino & PlatformIO?

Thank you for the reply, I tried running it in the Arduino IDE and got this error:

arm-none-eabi-g++: error: CreateProcess: No such file or directory

I am in a wee bit over my head so the problem is very likely that I am going to need to write a wrapper for the header files I am trying to use for the korg syro program.
 
Last edited:
I don't get that error message. What I get is that continuePlaying is undefined. In the original example code, continuePlaying is defined between startPlaying and stopPlaying but in your code it isn't there. I suspect that what happened was that you didn't need that function and removed it from the sketch but didn't remove the code that called it. The code compiles when that call is commented..


I actually caught that and edited the original post. The new code is in the original post and it does compile (almost) correctly in the Arduino IDE but not in PlatformIO. Its weird because I have never had issues with PIO before.
 
Yes, it probably does make a difference. Can you give it a try in Arduino, just to confirm whether the problem is the code itself or a difference between Arduino & PlatformIO?

Paul am I naive/wrong in thinking that there is a clean way to use the Korg Syro library from within my sketch without a boatload of converting? I am not opposed to figuring out how to do it but before I go down that road I dont want to overlook anything obvious.
 
a clean way to use the Korg Syro library from within my sketch without a boatload of converting?

Since that code does not appear to be designed to run on Teensy or any similar Arduino compatible board, I'm going to go with "no", though I suppose it does depend somewhat on the meaning of "clean" and "boatload".

Looks like any hope of using that would involve quite a bit of work to adapt it to compile and run properly.
 
Since that code does not appear to be designed to run on Teensy or any similar Arduino compatible board, I'm going to go with "no", though I suppose it does depend somewhat on the meaning of "clean" and "boatload".

Looks like any hope of using that would involve quite a bit of work to adapt it to compile and run properly.

I was afraid of that... I set a goal to figure it out so hell or high water I suppose I’ll come up with a way to do it! I did figure out that my issue ended up being related to recently moving my Arduino folder to my NAS and not properly repointing Pio and AIDE to the right spot. The code will compile now with the headers but getting the functions to work the right way is going to be the battle.
 
I've had a brief look at the code and one of the things you'll have to be mindful of is that it was written for processors which have gigabytes of ram. In such an environment, what often happens is that the code is written such that it never expects to run out of memory.
The Korg_syro code uses malloc and doesn't appear to be really careful about handling the case where malloc can return zero.
For example, in korg_syro_comp.c, the function SyroComp_Comp uses malloc to allocate a map_buffer and returns zero if the malloc fails. SyroComp_Comp is only called in one place, in korg_syro_volcasample.c, but the return value isn't tested for zero.
Similarly, SyroComp_GetCompSize returns zero if malloc fails but it is called in three places, none of which test for a return of zero.
This sort of thing can cause mysterious crashes.
If you're lucky, this is the only major problem and the rest of the conversion will be painless.
Good luck.

Pete
 
I've had a brief look at the code and one of the things you'll have to be mindful of is that it was written for processors which have gigabytes of ram. In such an environment, what often happens is that the code is written such that it never expects to run out of memory.
The Korg_syro code uses malloc and doesn't appear to be really careful about handling the case where malloc can return zero.
For example, in korg_syro_comp.c, the function SyroComp_Comp uses malloc to allocate a map_buffer and returns zero if the malloc fails. SyroComp_Comp is only called in one place, in korg_syro_volcasample.c, but the return value isn't tested for zero.
Similarly, SyroComp_GetCompSize returns zero if malloc fails but it is called in three places, none of which test for a return of zero.
This sort of thing can cause mysterious crashes.
If you're lucky, this is the only major problem and the rest of the conversion will be painless.
Good luck.

Pete

Thank you! I don't know very much C programming but I have been meaning to learn so it's probably a good time to jump in to it. I appreciate you taking the time to offer some ideas of where to start! The Syros stuff can do more than I need, I am really only interested in the audio conversion and Sending/deleting saved samples and not any of the pattern stuff so hopefully that will make it a little simpler too.
 
I've had another look at the code and compiled the example code on my PC. It runs without any problem. I then added some debugging statements to print out the size of memory requested in each call to malloc. This is the output:
Code:
malloc:    2048 map_buffer 1
malloc:     480 handle_size
malloc:    2048 map_buffer 1
malloc:   13568 comp_buf
malloc:    2048 map_buffer 2
malloc: 1321004 size_dest
As you can see, a Teensy 4 would have no problem handling the first 5 allocations but the last one isn't going to work. What that does is allocate enough space for the entire output file - a 16-bit 44.1kHz stereo WAV.
I don't know if I'll dig any deeper, but what you'll have to figure out is how to write that file in smaller pieces that the T4 can accommodate.

Pete
 
It turned out to be easy to change the code so that it wrote the data in smaller pieces (256 byte blocks).
Having done that it was also easy to change it so that it writes the data as audio to the audio board, which I think might be more useful.
The attached zip should be unzipped into your teensy libraries directory. It contains two sketches in the "example" subdirectory.
korg_syro_example_1
This reads the example WAV file from the distribution and converts it into a (much larger) WAV file containing the audio which would be sent to the volca.
korg_syro_example_2
This also converts the example WAV file but it sends the audio out the headphones and line output on a Teensy audio board.

I've tested these on a Teensy 4 but they should work on Teensy 3.* (with audio board for the second example).

If you can try these out, I'd like to know whether the second example allows you to upload that sample to a Volca.

Pete
View attachment volcasample_teensy.zip
 
It turned out to be easy to change the code so that it wrote the data in smaller pieces (256 byte blocks).
Having done that it was also easy to change it so that it writes the data as audio to the audio board, which I think might be more useful.
The attached zip should be unzipped into your teensy libraries directory. It contains two sketches in the "example" subdirectory.
korg_syro_example_1
This reads the example WAV file from the distribution and converts it into a (much larger) WAV file containing the audio which would be sent to the volca.
korg_syro_example_2
This also converts the example WAV file but it sends the audio out the headphones and line output on a Teensy audio board.

I've tested these on a Teensy 4 but they should work on Teensy 3.* (with audio board for the second example).

If you can try these out, I'd like to know whether the second example allows you to upload that sample to a Volca.

Pete
View attachment 18975

I was not expecting anyone to take the time to dig this far into this, thank you! Sincerely! I was getting ready to jump back in tomorrow morning after a long work week last week and this was a very exciting surprise. I will let you know once I get it fired up in the morning!
 
It turned out to be easy to change the code so that it wrote the data in smaller pieces (256 byte blocks).
Having done that it was also easy to change it so that it writes the data as audio to the audio board, which I think might be more useful.
The attached zip should be unzipped into your teensy libraries directory. It contains two sketches in the "example" subdirectory.
korg_syro_example_1
This reads the example WAV file from the distribution and converts it into a (much larger) WAV file containing the audio which would be sent to the volca.
korg_syro_example_2
This also converts the example WAV file but it sends the audio out the headphones and line output on a Teensy audio board.

I've tested these on a Teensy 4 but they should work on Teensy 3.* (with audio board for the second example).

If you can try these out, I'd like to know whether the second example allows you to upload that sample to a Volca.

Pete
View attachment 18975

Tried two different SD cards and redownloaded the Korg library just to make sure I had not ever messed with that sample file. I have a couple T4 and music shields, I am going to solder one up and try it there. It could just be an issue with the 3.6
 
I forgot to mention that on your SD card, the sample input WAV file must be named 02Kick3.wav. The original name in the distribution, "02 Kick 3.wav", is too long to fit the 8.3 format required for the SD card on the Teensy.

Pete
 
I forgot to mention that on your SD card, the sample input WAV file must be named 02Kick3.wav. The original name in the distribution, "02 Kick 3.wav", is too long to fit the 8.3 format required for the SD card on the Teensy.

Pete

Aha! That took care of it for the T4. I am getting the signal to the VS now but its throwing an error when it tries to read the stream. They are notoriously finicky about the volume level and any other noise interference so I am messing around with the output volume from the music shield to see if I can zero in on where it isnt loud enough to be recognized as opposed to being to loud. Thank you again! This will give me a gigantic leg up learning how to deploy this when it comes time to adding the input into the equation.
 
Are you using the headphone output and do you have the volume control potentiometer on the audio board?
If so, you could try changing this:
Code:
  sgtl5000_1.volume(0.4);
to this:
Code:
  int n = analogRead(15);
  sgtl5000_1.volume(n / 1023.);
Serial.printf("volume = %4.2f\n",n/1023.);
Set the pot to a low volume to start with and increase it a bit each time it fails to decode. The sketch prints out the volume being used, so if it works you'll know what to use as a "hard-coded" value.

Pete
 
Status
Not open for further replies.
Back
Top