|
332
|
Using Arduino / Audio / Re: Class for playing MIDI files from the Arduino - testers needed
|
on: December 30, 2012, 04:27:52 pm
|
|
I take your point, but they are actually not allowed to exist in the stream according to the Standard MIDI File documentation. If they are in there then either the file should be considered invalid (ie, abandon it) or the sync has to be to the next byte with a top bit not set, which should be the next deltaT.
The problem with MIDI files is that they are sequential - each note or event is defined in a time offset (deltaT) from the previous one and if you sync forward you get out of time sequence with respect to the other tracks. I actually had this happening early in the piece and it sounds awful.
I'll need to think about this one.
Edit - on reflection, the most straightforward way is to make the track invalid (ie, mark it as end of track) and stop playing it. This allows the other tracks to play on and the file is not totally lost.
|
|
|
|
|
333
|
Using Arduino / Audio / Re: Class for playing MIDI files from the Arduino - testers needed
|
on: December 30, 2012, 02:50:15 pm
|
Thanks robtillart for taking the time to look and comment. starnges that an destructor calls initialize Initially I had some memory allocation going on and I had to free memory (that was being done in close()), so the destructor needed to call close(). I have renamed initialise() to resetTrack() which may give us all less of an uncomfortable feeling. saw you have a dump mode (but it is a cooked dump not a raw dump) There is a sketch that does a raw dump of the data in the chunks after the header, without using the library. I also use a utility called "MIDI File Analyzer" (picked up somewhere off a Google link) that basically agrees with my own dump(s) of the files, so I am have a high confidence the dumps are correct. not handling all values between 0xf1 ... 0xff: Yes, correct. These values are real time valuies that appear in a MIDI live stream as control messages but are not valid in a file - 0xf1 is undefined, 0xf2 is Start a sequence, 0xf3 is Continue sequence. 0xf4 is Stop sequence, 0xf5 is undefined, 0xf6 is Active Sense (like a watchdog timer), 0xff is Reset System. All others in this range should be processed. x not used A leftover from when I had an intermediate result being calculated. syntactically wrong as you should use the boolean && not the bitwise & and it can be faster Agree. Suggested version also saves 1 byte of stack space :-) many loops use int i; you could check if uint8_t is enough ? Good point, will check. So many #if 's makes me wonder if you could not better Great point here. I have done what you suggested before and I don't know why I didn't do it here as well. This will also make the code more maintanable, as an alternative output stream is easier to implement if needed. I'll post an updated version of the library once implemented and tested.
|
|
|
|
|
337
|
Using Arduino / Audio / Library for playing MIDI files from the Arduino
|
on: December 29, 2012, 09:17:12 pm
|
|
Update - See last posting. I have been working on a class to read MIDI files (Standard MIDI Format) from an SD card and play them through a MIDI serial interface on the Arduino. My aim is to be able to play any MIDI file as long as it is properly constructed.
This code is now very stable but at a point where (a) I have been looking at it too long, and (b) I need input from people who know more about MIDI than I do.
The class generally works ok, but there are a few files that do not play well (or at all) and I am stumped as to what makes these files 'special'. All the MIDI files are playable on my Windows PC and I can't see why is in the data that makes them not play when I print out what is in the file (using the dump() method in the class).
All the library code, some example program files that call the library, and a collection of MIDI files are attached. There is a dependency on other libraries - MIDI, SdFat and Flash. Locations to get these is documented in MIDIFile.h. You should also have a working MIDI serial interface - OUT is the only channel used form the Arduino for this software.
The problems I am experiencing are probably best explained in the MIDIFile_Play example - some of the files play really well and other sound strange or don't even start. My feeling is that I am not getting some of the time signals correct as the Time Signature META event is only partially processed, but I can't see how what I have ignore affects anything (ignorance here, probabaly, as I am not a musician).
Happy to get feedback and or help on sorting these issues out from anyone with some free time and interest to test or review the code.
Thanks in advance.
|
|
|
|
|
338
|
Using Arduino / Programming Questions / Re: what is Map instruction do ???
|
on: December 29, 2012, 04:06:24 am
|
|
map() takes an input range and maps it to an output range (ie, it scales).
So if the input value was 2 and the range was between 0 and 10, then mapping it to the new range 0 to 100 will return the value 20. Note that if you had 11 in the first instance it would return 110, so you often need to use constrain() if you do not want these values outside the full range.
|
|
|
|
|
340
|
Using Arduino / Programming Questions / Re: call of overloaded with average lib !
|
on: December 24, 2012, 02:42:38 pm
|
Interrupt:87: error: call of overloaded 'mean(volatile int [20], int)' is ambiguous /Users/florent/Documents/Arduino/libraries/Average/Average.h:39: note: candidates are: int mean(int*, int) <near match> /Users/florent/Documents/Arduino/libraries/Average/Average.h:40: note: unsigned int mean(unsigned int*, int) <near match>
Looks like you are trying to pass an array to the function. Don't put the array subscript in the mean function call ("'mean(volatile int [20], int)'"). The name of the array is all you need as that is a pointer to the data. I am guessing the second parameter is the size of the array, and that is an integer.
|
|
|
|
|
342
|
Using Arduino / Programming Questions / Re: Quick question about populating arrays
|
on: December 21, 2012, 04:55:53 am
|
You can. You need to enclose all the elements for a structure within curly braces and separate these groups by comms.. Essentially each array element is a group of variables instead of the individual items if a simple array. struct_type data[3] = {{1,2,3},{3,4,5},{6,7,8}};
|
|
|
|
|
344
|
Using Arduino / Programming Questions / Library referencing other libraries will not compile - SOLVED
|
on: December 21, 2012, 02:04:42 am
|
I am creating a library (called MIDIFile) that implements a class that can be used to read a MIDI file from an SD card and stream it to a MIDI device. I am using the SDFat library to read the SD card, so this is referenced in the library. When I try and compile a test program, I get definition errors for items that are defined in the SDFat library. It just seems like the compiler cannot find the header file and no matter what combinations I try (order of includes, bracket types, relative paths) they don't seem to make any difference. MIDI_FileRead2.ino:1:19: warning: SDFat.h: No such file or directorySDFile and my new library are in the Sketchbook/libraries folder. I am running windows and I have the IDE 1.0.3. Clearly I am not adding stuff in the header files in the right order, so here are the start of the files with the include sequence, and the erroe message I get. I am sure someone will have solved this before... Midifile.h - the library header file #ifndef _MIDIFILE_H #define _MIDIFILE_H
// Arduino MIDI File library // // A class which can read Standard MIDI files. //
#include <Arduino.h> #include <SdFat.h>
class MidiFile { public: MidiFile(void); MidiFile(uint8_t ss); MidiFile(const char* aFile); MidiFile(uint8_t ss, const char* aFile);
~MidiFile(void);
MidiFile.cpp - library code file implementing the class // Arduino MIDI File library // // A class which can read Standard MIDI files. //
#include <string.h> #include "MidiFile.h"
My test program #include <SDFat.h> #include <MidiFile.h>
/* * SD chip select pin. Common values are: * Arduino Ethernet shield, pin 4. */ #define SD_SELECT 4 #define MIDI_FILE "LOOPDEMO.MID"
MidiFile SMF(SD_SELECT, MIDI_FILE);
/* void dumpBuffer(SdFile *f, int len) { for (int i=0; i<len; i++) { uint8_t c = f->read(); if ((i!=0) && ((i%8) == 0)) Serial.println(); Serial.print(' '); if (c<=0xf) Serial.print('0'); Serial.print(c, HEX); } } */ void DumpSMF(void) { Serial.println(SMF.getFilename()); Serial.print("File Version:\t"); Serial.println(SMF.getFormat()); Serial.print("Tracks:\t\t"); Serial.println(SMF.getTrackCount()); Serial.print("Speed:\t\t"); Serial.println(SMF.getTicksPerQuarterNote()); }
void setup(void) { Serial.begin(57600); Serial.println("[MIDI file reader]"); SMF.load(); DumpSMF(); // close the file: SMF.close(); }
void loop(void) { }
Error messages (compiler verbose turned on): F:\arduino\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=103 -IF:\arduino\hardware\arduino\cores\arduino -IF:\arduino\hardware\arduino\variants\standard -IF:\Marco\Documents\Programming\Arduino\Sketchbook\libraries\MIDIFile C:\Users\Marco\AppData\Local\Temp\build6922185689476771770.tmp\MIDI_FileRead2.cpp -o C:\Users\Marco\AppData\Local\Temp\build6922185689476771770.tmp\MIDI_FileRead2.cpp.o MIDI_FileRead2.ino:1:19: warning: SDFat.h: No such file or directory In file included from MIDI_FileRead2.ino:2: F:\Marco\Documents\Programming\Arduino\Sketchbook\libraries\MIDIFile/MidiFile.h:33:19: warning: SdFat.h: No such file or directory In file included from MIDI_FileRead2.ino:2: F:\Marco\Documents\Programming\Arduino\Sketchbook\libraries\MIDIFile/MidiFile.h:132: error: 'SdFat' does not name a type F:\Marco\Documents\Programming\Arduino\Sketchbook\libraries\MIDIFile/MidiFile.h:133: error: 'SdFile' does not name a type F:\Marco\Documents\Programming\Arduino\Sketchbook\libraries\MIDIFile/MidiFile.h:136: error: 'SdFile' has not been declared F:\Marco\Documents\Programming\Arduino\Sketchbook\libraries\MIDIFile/MidiFile.h:137: error: 'SdFile' has not been declared
|
|
|
|
|
345
|
Using Arduino / Programming Questions / Re: Replace Buttons with LDR's
|
on: December 20, 2012, 03:17:38 pm
|
Can't test this as I have not got your libraries, but this the changes are implemented: #include <FatReader.h> #include <SdReader.h> #include <avr/pgmspace.h> #include "WaveUtil.h" #include "WaveHC.h"
SdReader card; // This object holds the information for the card FatVolume vol; // This holds the information for the partition on the card FatReader root; // This holds the information for the filesystem on the card FatReader f; // This holds the information for the file we're play
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
#define DEBOUNCE 5 // button debouncer
// here is where we define the buttons that we'll use. button "1" is the first, button "6" is the 6th, etc /// --- byte buttons[] = {14, 15, 16, 17, 18, 19}; byte buttons[] = {A0, A1, A2, A3, A4, A5};
// This handy macro lets us determine how big the array up above is, by checking the size #define NUMBUTTONS sizeof(buttons)/sizeof(buttons[0]) #define ON_THRESHOLD 512 // change to suit values retruned from LDR. Values greater will be ON
// we will track if a button is just pressed, just released, or 'pressed' (the current state volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];
// this handy function will return the number of bytes currently free in RAM, great for debugging! int freeRam(void) { extern int __bss_end; extern int *__brkval; int free_memory; if((int)__brkval == 0) { free_memory = ((int)&free_memory) - ((int)&__bss_end); } else { free_memory = ((int)&free_memory) - ((int)__brkval); } return free_memory; }
void sdErrorCheck(void) { if (!card.errorCode()) return; putstring("\n\rSD I/O error: "); Serial.print(card.errorCode(), HEX); putstring(", "); Serial.println(card.errorData(), HEX); while(1); }
void setup() { byte i;
// set up serial port Serial.begin(9600); putstring_nl("WaveHC with "); Serial.print(NUMBUTTONS, DEC); putstring_nl("buttons");
putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad Serial.println(freeRam()); // if this is under 150 bytes it may spell trouble!
// Set the output pins for the DAC control. This pins are defined in the library pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT);
// pin13 LED pinMode(13, OUTPUT);
// Make input & enable pull-up resistors on switch pins for (i=0; i< NUMBUTTONS; i++) { pinMode(buttons, INPUT); digitalWrite(buttons, HIGH); }
// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you if (!card.init()) { //play with 8 MHz spi (default faster!) putstring_nl("Card init. failed!"); // Something went wrong, lets print out why sdErrorCheck(); while(1); // then 'halt' - do nothing! }
// enable optimize read - some cards may timeout. Disable if you're having problems card.partialBlockRead(true);
// Now we will look for a FAT partition! uint8_t part; for (part = 0; part < 5; part++) { // we have up to 5 slots to look in if (vol.init(card, part)) break; // we found one, lets bail } if (part == 5) { // if we ended up not finding one smiley-sad putstring_nl("No valid FAT partition!"); sdErrorCheck(); // Something went wrong, lets print out why while(1); // then 'halt' - do nothing! }
// Lets tell the user about what we found putstring("Using partition "); Serial.print(part, DEC); putstring(", type is FAT"); Serial.println(vol.fatType(),DEC); // FAT16 or FAT32?
// Try to open the root directory if (!root.openRoot(vol)) { putstring_nl("Can't open root dir!"); // Something went wrong, while(1); // then 'halt' - do nothing! }
// Whew! We got past the tough parts. putstring_nl("Ready!");
TCCR2A = 0; TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;
//Timer2 Overflow Interrupt Enable TIMSK2 |= 1<<TOIE2;
}
SIGNAL(TIMER2_OVF_vect) { check_switches(); }
void check_switches() { static byte previousstate[NUMBUTTONS]; static byte currentstate[NUMBUTTONS]; byte index;
for (index = 0; index < NUMBUTTONS; index++) { currentstate[index] = analogRead(buttons[index]) >= ON_THRESHOLD; // read the LDR 'button'
/* Serial.print(index, DEC); Serial.print(": cstate="); Serial.print(currentstate[index], DEC); Serial.print(", pstate="); Serial.print(previousstate[index], DEC); Serial.print(", press="); */
if (currentstate[index] == previousstate[index]) { if ((pressed[index] == LOW) && (currentstate[index] == LOW)) { // just pressed justpressed[index] = 1; } else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) { // just released justreleased[index] = 1; } pressed[index] = !currentstate[index]; // remember, digital HIGH means NOT pressed } //Serial.println(pressed[index], DEC); previousstate[index] = currentstate[index]; // keep a running tally of the buttons } }
void loop() { byte i; static byte playing = -1;
if (pressed[0]) { if (playing != 0) { playing = 0; playfile("DO.WAV"); } } else if (pressed[1]) { if (playing != 1) { playing = 1; playfile("RE.WAV"); } } else if (pressed[2]) { if (playing != 2) { playing = 2; playfile("MI.WAV"); } } else if (pressed[3]) { if (playing != 3) { playing = 3; playfile("FA.WAV"); } } else if (pressed[4]) { if (playing != 4) { playing = 4; playfile("SO.WAV"); } } else if (pressed[5]) { if (playing != 5) { playing = 5; playfile("LA.WAV"); } }
if (! wave.isplaying) { playing = -1; } }
// Plays a full file from beginning to end with no pause. void playcomplete(char *name) { // call our helper to find and play this name playfile(name); while (wave.isplaying) { // do nothing while its playing } // now its done playing }
void playfile(char *name) { // see if the wave object is currently doing something if (wave.isplaying) {// already playing something, so stop it! wave.stop(); // stop it } // look in the root directory and open the file if (!f.open(root, name)) { putstring("Couldn't open file "); Serial.print(name); return; } // OK read the file and turn it into a wave object if (!wave.create(f)) { putstring_nl("Not a valid WAV"); return; }
// ok time to play! start playback wave.play(); }
|
|
|
|
|