Go Down

Topic: MIDI library conflict? (Read 4918 times) previous topic - next topic

deseipel




Quote
I believe the sketch is stopping around   err = SMF.load();.   


This is actually in loop() and not in setup(), so you are contradicting previous information.






I was referring to another sketch i believe.  Sorry I wasn't clear.  I'm going through  a lot of testing and sometimes the sketches are different.

deseipel

to clarify, this is one that was looping in setup;  I have a feeling the 2nd SD.begin is not needed. 


Code: [Select]
void setup() {


MIDI.begin(MIDI_CHANNEL_OMNI);
//  Serial.begin(57600);
   pinMode(MIDI_ENABLE, OUTPUT);      // sets the digital pin as output
  digitalWrite(MIDI_ENABLE, HIGH);
  //  MIDI.turnThruOff();

  //   MIDI.setHandleClock ( HandleClock );


  //MIDIfile & SD card setups
  // Initialise SD
  if (!SD.begin(chipSelect, SPI_HALF_SPEED))SD.initErrorHalt();
  // Serial.println("begin success");

  SD.begin(chipSelect, SPI_HALF_SPEED);

  // Initialise MIDIFile
  SMF.begin(&SD);
  SMF.setMidiHandler(midiCallback);
//  SMF.setSysexHandler(sysexCallback);
//MIDI.setHandleNoteOn(HandleNoteOn);
MIDI.sendProgramChange(P,10);   
}

marco_c

Quote
I have a feeling the 2nd SD.begin is not needed.


Definitely
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

deseipel

I suppose the good thing here is that I'm learning. 

The goal of this project is to have something that :

1.  can map midi notes to midi events (program change)
2. establishes a midi master clock.
3.  plays/loops midi sequences

the hardware I currently have is a Ruggeduino UNO, Ruggeduino MIDI shield and a ITEAD SD Card.   I can envision and LED in the future as well.  Would a MEGA have enough memory?   I guess I'm wondering if it's a memory issue or not.  166 bytes seems low, but is it?

marco_c

The MEGA has more RAM and more program memory as well. It also has a lot more I/O pins.

166 bytes left over is fine if it never changes. It means that you have enough RAM. Remember that you don't needs lots, you just need enough. There are things you can do (like use flash RAM to store strings, making loop counters uint8 instead of int) that will increase the amount of RAM available for other things.

RAM is used by 2 things - one is the program stack and the other the memory heap. The stack usually grows from the bottom up and the heap is allocated from the top down. So if you run out of space, the stack and the heap collide in the middle.

The stack hold all the temporary variables that are being used by a function when it is called and the return address. So, having lots of nested function calls and/or lots of temporary variables makes the stack grow faster.

Most libraries, if they use RAM, will have allocated all they need after the setup() or begin() type routines. Some, however, will allocate memory as required, and this is where the 166 bytes may cause issues. I know that MIDIFile will not allocate additional RAM, and you should look at the MIDI library for malloc(), alloc() or new() function calls, and when they occur.

Unfortunately, when you use someone else's library this stuff is hard to determine and depends on the skill of the library builder (which in many cases is not high, in Arduino land). Remember too that adding debugging messages takes up space and may sometimes be the cause of problems, especially when you are close to full RAM usage.

If you have removed the strings as suggested and you now see more free RAM available, but still see the 'reset' problems, then I am guessing that it is probably not RAM starvation but something else.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

deseipel

i don't get the sense it's a RAM issue. But it might very well be.  I'm not sure how to confirm it.  I have 162 bytes at the furthest point at which I can get a serial reading.  At the SMF.load point of the code is where all serial comms appear to stop.  If I comment out all the MIDI library stuff, add back Serial commands,  the code runs, its as soon as I add the #includes MIDI.h, is when it stops

And it appears that the function SMF.load() is where the code stops..  So, this makes me think there's something with the load event that causes it to be in conflict. 

do I need to somehow combine these libraries into one?  Would that tell me anything more? 

The other option is simply to buy another arduino + MIDI shield.  then I'd have one to map messages and provide clock and one to play midi files.  it might actually be better that way.  not sure.  I'd rather have one box, but it wouldn't be the end of the world.

marco_c

If you are narrowing it down to SMF.load() then start putting debugging message in the SMF.load() routine and see if that is going on there.

The load() routine is the first time that the SDFat libraries are called to open a file, so there could be interactions there.

Combining libraries is not a good idea, especially as this will require an even greater knowledge of coding that what you need to do what you are doing now.

There is no easy way to debug this other than keep tracing to where the thing dips out, including in the libraries.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

deseipel

What about the dumps in the Midifile lib?
Also noticed that the sdfat has some serial based functions. 


marco_c

#38
Dec 14, 2013, 08:35 am Last Edit: Dec 14, 2013, 09:33 pm by marco_c Reason: 1
Midifile lib dumps are a formatted version of what is in the SD file, they won't help you as the library by itself works fine. Unless you have turned them on they disappear through the magic of macro substitution.

No idea about the SD card library.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

deseipel

I guess I don't know where to go from here.  I'm gonna try to confirm some things using a couple example sketches.  I'm still wondering if the midifile library breaks a MIDI example sketch and vice versa.  I think the issue might be the sdfat library and the MIDI library but not sure.  Not sure how to solve this. 

deseipel

Does MIDIfile try to load the entire MIDI file into RAM?  or read it from SD as needed? 

I've gone through everything in the the load part of the MIDIfile code and I have some questions:

Code: [Select]
for (uint8_t i = 0; i<_trackCount; i++)
   {
   int err;
   
   if ((err = _track[i].load(i, this)) != -1)
   {
   _fd.close();
   return((10*(i+1))+err);
   }
   }

  return(-1);



if I wanted to run this code in a sketch, what would I replace "_track" with?  I guess what I need to understand is what is happening when the load event occurs, because that's where it breaks.  not being able to use Serial to debug this is quite a challenge.  I'm stuck with playing notes for validation. 

I suppose the options at this point are:;

1.  abandon the MIDI library and use Serial
2.  continue to try to figure out what's wrong with this.
3.  Buy another Arduino + MIDI Shield and have it be a stand alone MIDI player using this MIDIfile library (but then I'd ultimately hae to deal with it's inablity to natively sync with other MIDI devices. ) 
4.  Buy an AKAI MPC
5.  Write my own library

deseipel

#41
Dec 16, 2013, 09:35 pm Last Edit: Dec 16, 2013, 09:37 pm by deseipel Reason: 1

what's interesting (I guess) is that everything here works, except the MIDI calls.  I have a ruggeduino MIDI shield and Im playing the MIDI file over softserial and attempting to use the MIDI library over regular serial.  

MIDI.NoteOn produces no sound
Serial.write produces sound

???

Why would Serial.write work and MIDI.NoteOn not work?   The MIDI library uses the Serial port.   ???


Code: [Select]


#include <SoftwareSerial.h>


// Test playing a succession of MIDI files from the SD card.
// Example program to demonstrate the use of the MIDFile library
// Just for fun light up a LED in time to the music.
//
// Hardware required:
// SD card interface - change SD_SELECT for SPI comms
// 3 LEDs (optional) - to display current status and beat.
// Change pin definitions for specific hardware setup.

#include <SdFat.h>
#include <MIDIFile.h>
#include <MIDI.h>
SoftwareSerial SSerial(2, 3); // RX, TX
long bpm = 120;
long tempo = 1000/(bpm/60);
 unsigned long currentMillis = millis();
long prevmillis = 0;
long interval = tempo/24;    //interval is the number of milliseconds defined by tempo formula.




#define SERIAL_RATE 31250



//#define DEBUG(x) Serial.print(x)
//#define DEBUGX(x) Serial.print(x, HEX)





// SD chip select pin for SPI comms.
// Arduino Ethernet shield, pin 4.
// Default SD chip select is the SPI SS pin (10).
// Other hardware will be different as documented for that hardware.
#define  SD_SELECT  10

// LED definitions for user indicators
//#define READY_LED 7 // when finished
//#define SMF_ERROR_LED 6 // SMF error
//#define SD_ERROR_LED 13 // SD error
//#define BEAT_LED 6 // toggles to the 'beat'

#define WAIT_DELAY 2000 // ms

#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))

// The files in the tune list should be located on the SD card
// or an error will occur opening the file and the next in the
// list will be opened if that exists.
char *tuneList[] =
{
"LOOPDEMO.MID"
};

// These don't play as they need more than 16 tracks but will run if MIDIFile.h changed
//#define MIDI_FILE  "SYMPH9.MID" // 29 tracks
//#define MIDI_FILE  "CHATCHOO.MID" // 17 tracks
//#define MIDI_FILE  "STRIPPER.MID" // 25 tracks

SdFat SD;
MIDIFile SMF;

void midiCallback(midi_event *pev)
// Called by the MIDIFile library when a file event needs to be processed
// thru the midi communications interface.
// This callback is set up in the setup() function.
{

if ((pev->data[0] >= 0x80) && (pev->data[0] <= 0xe0))
{
SSerial.write(pev->data[0] | pev->channel);
SSerial.write(&pev->data[1], pev->size-1);
}
else
{SSerial.write(pev->data, pev->size);}


//  DEBUG("\nM T");
//  DEBUG(pev->track);
//  DEBUG(":  Ch ");
//  DEBUG(pev->channel+1);
//  DEBUG(" Data ");
//  for (uint8_t i=0; i<pev->size; i++)
//  {
// DEBUGX(pev->data[i]);
//    DEBUG(' ');
//  }
}

void sysexCallback(sysex_event *pev)
// Called by the MIDIFile library when a system Exclusive (sysex) file event needs
// to be processed thru the midi communications interface. MOst sysex events cannot
// really be processed, so we just ignore it here.
// This callback is set up in the setup() function
{
//  DEBUG("\nS T");
//  DEBUG(pev->track);
//  DEBUG(": Data ");
//  for (uint8_t i=0; i<pev->size; i++)
//  {
//    DEBUGX(pev->data[i]);
// DEBUG(' ');
//  }
}

void midiSilence(void)
// Turn everything off on every channel.
// Some midi files are badly behaved and leave notes hanging, so between songs turn
// off all the notes and sound
{
midi_event ev;

// All sound off
// When All Sound Off is received all oscillators will turn off, and their volume
// envelopes are set to zero as soon as possible.
ev.size = 0;
ev.data[ev.size++] = 0xb0;
ev.data[ev.size++] = 120;
ev.data[ev.size++] = 0;

for (ev.channel = 0; ev.channel < 16; ev.channel++)
midiCallback(&ev);
}

// Generate a MIDI OUT note-on event.
void note_on()
{
 SSerial.write(0x90);         // Note on
 SSerial.write(60);
 SSerial.write(120);
 SSerial.write(1);
}

// Generate a MIDI OUT note-off event.
void note_off()
{

 SSerial.write(0x80);        // Note off
 SSerial.write(60);
 SSerial.write(32);
 SSerial.write(1);
}

void Sync(){


 if(currentMillis - prevmillis > interval) {
   // save the last time.
   prevmillis = currentMillis;
 MIDI.sendRealTime(Clock);    
 }
}


void setup(void)
{


 SSerial.begin(SERIAL_RATE);
//Serial.begin(9600);
MIDI.begin(31250);

   pinMode(A5, OUTPUT);      // sets the digital pin as output
 digitalWrite(A5, HIGH);
//  DEBUG("\n[MidiFile Play List]");

 // Initialise SD
 if (!SD.begin(SD_SELECT, SPI_HALF_SPEED))
 {
//    DEBUG("\nSD init fail!");

 
 }

 // Initialise MIDIFile
 SMF.begin(&SD);
 SMF.setMidiHandler(midiCallback);
 SMF.setSysexHandler(sysexCallback);


}

//void tickMetronome(void)
//// flash a LED to the beat
//{
// static uint32_t lastBeatTime = 0;
// static boolean inBeat = false;
// uint16_t beatTime;
//
// beatTime = 60000/SMF.getTempo(); // msec/beat = ((60sec/min)*(1000 ms/sec))/(beats/min)
// if (!inBeat)
// {
// if ((millis() - lastBeatTime) >= beatTime)
// {
// lastBeatTime = millis();
//
// inBeat = true;
// }
// }
// else
// {
// if ((millis() - lastBeatTime) >= 100) // keep the flash on for 100ms only
// {
//
// inBeat = false;
// }
// }
//
//}

void loop(void)
{MIDI.read();
// SSerial.read();
//Sync();
MIDI.send(NoteOn, 65, 120, 1);
delay(500);
MIDI.send(NoteOff, 65, 120, 1);
//note_on();
//delay(500);
//note_off();

   int  err;

for (uint8_t i=0; i<ARRAY_SIZE(tuneList); i++)
{
 // reset LEDs



 // use the next file name and play it
 SMF.setFilename(tuneList[i]);

 err = SMF.load();

 if (err != -1)
 {
// DEBUG("\nSMF load Error ");
// DEBUG(err);

delay(WAIT_DELAY);
 }
 else
 {
// play the file
while (!SMF.isEOF())
{
 
if (SMF.getNextEvent())
Sync();
}

// done with this one
SMF.close();
midiSilence();

// signal finsh LED with a dignified pause

delay(WAIT_DELAY);
 }
}
}


also:  the script as shown here plays through once and then stops.  more strange.

deseipel

Update: I dumped the MIDI lib and I'm using straight up serial

Code here

https://github.com/deseipel/Arduino/blob/master/MIDIBlackBox2.0


deseipel

ok, similar problem with the MIDIFile library.  This time, all I did was add it to a sketch and

Code: [Select]
MIDIFile SMF;

breaks it. 

I have the Ruggeduino, MIDI shield & Adafruit 1.8" TFT & SD card shield. 


Code: [Select]
#include <MIDIFile.h>
#include <MIDIHelper.h>


#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#include <SoftwareSerial.h>
//#include <SdFatUtil.h>
#include <SdFat.h>
#include <SPI.h>




/// Edit for Shield Pinouts!
#define SD_CS    4  // Chip select line for SD card
#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  0  // Reset line for TFT (or connect to +5V)
#define ADA_JOYSTICK 3
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

SdFat SD;
MIDIFile SMF;  // or this breaks it.

deseipel

Code: [Select]
#include <MIDIFile.h>
#include <MIDIHelper.h>


#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#include <SoftwareSerial.h>
//#include <SdFatUtil.h>
#include <SdFat.h>
#include <SPI.h>




/// Edit for Shield Pinouts!
#define SD_CS    4  // Chip select line for SD card
#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  0  // Reset line for TFT (or connect to +5V)
#define ADA_JOYSTICK 3
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
//MIDIFile SMF;  // or this breaks it.  POSSIBLY A CONFLICT WITH SERIAL ?
SdFat SD;



////////////////////////////////////////////////////////////////////////////////
void setup(){
 tft.initR( INITR_BLACKTAB );    //  "tab color" from screen protector; there's RED and GREEN, too.

tft.setTextColor(RED);

tft.setTextSize(1); //  1 = 5x8, 2 = 10x16; chars leave blank pixel on bottom
tft.println("TFT Setup Completed");
//delay(500);
// cls();
//Serial.begin(9600);
//SMF.begin(&SD);
//if (!SD.begin(SD_CS, SPI_HALF_SPEED)) SD.initErrorHalt();
//  if (!SD.begin(SD_CS, SPI_HALF_SPEED))
// {
      // Serial.print("\nSD init fail!");
//   tft.println("SD init fail!");
 //  return;
// }
//Serial.println("draw_menu");
draw_menu();
//Serial.println("Setup completed");
//delay(500);
//cls();
}

////////////////////////////////////////////////////////////////////////////////
//  clearscreen helper for tft
void cls() {
tft.fillScreen(BLACK);
tft.setCursor(0, 2);
}



////////////////////////////////////////////////////////////////////////////////
void loop() {

if( doMenu() ){

 
//  something happened with joystick, an update() action could be called here
}

}


Go Up