Browse Source

Merge in changes from LenShustek/miditones with latest updates, including building correctly on Mac

dds
Dean Blackketter 8 years ago
parent
commit
c53268213d
1 changed files with 80 additions and 64 deletions
  1. +80
    -64
      extras/miditones/miditones.c

+ 80
- 64
extras/miditones/miditones.c View File

* Convert a MIDI file into a bytestream of notes * Convert a MIDI file into a bytestream of notes
* *
* *
* (C) Copyright 2011, Len Shustek
* (C) Copyright 2011,2013,2015,2016 Len Shustek
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as * it under the terms of version 3 of the GNU General Public License as
* -Changed to allow compilation and execution in 64-bit environments * -Changed to allow compilation and execution in 64-bit environments
* by using C99 standard intN_t and uintN_t types for MIDI structures, * by using C99 standard intN_t and uintN_t types for MIDI structures,
* and formatting specifications like "PRId32" instead of "ld". * and formatting specifications like "PRId32" instead of "ld".
* 04 April 2015, L. Shustek, V1.7
* -Made friendlier to other compilers: import source of strlcpy and strlcat,
* fixed various type mismatches that the LCC compiler didn't fret about.
* Generate "const" for data initialization for compatibility with Arduino IDE v1.6.x.
* 23 January 2016, D. Blackketter, V1.8
* -Fix warnings and errors building on Mac OS X via "gcc miditones.c"
* 25 January 2016, D. Blackketter, Paul Stoffregen, V1.9
-Merge in velocity output option from Arduino/Teensy Audio Library
*/ */
// Sept 2014 - Add option for velocity output


#define VERSION "1.6"
#define VERSION "1.9"




/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* *
* If the high-order bit of the byte is 1, then it is one of the following commands: * If the high-order bit of the byte is 1, then it is one of the following commands:
* *
* 9t nn Start playing note nn on tone generator t. Generators are numbered
* 9t nn [vv] Start playing note nn on tone generator t. Generators are numbered
* starting with 0. The notes numbers are the MIDI numbers for the chromatic * starting with 0. The notes numbers are the MIDI numbers for the chromatic
* scale, with decimal 60 being Middle C, and decimal 69 being Middle A (440 Hz). * scale, with decimal 60 being Middle C, and decimal 69 being Middle A (440 Hz).
* if the -v option is enabled, a second byte is added to indicate velocity
* *
* 8t Stop playing the note on tone generator t. * 8t Stop playing the note on tone generator t.
* *
void SayUsage(char *programName){ void SayUsage(char *programName){
static char *usage[] = { static char *usage[] = {
"Convert MIDI files to an Arduino PLAYTUNE bytestream", "Convert MIDI files to an Arduino PLAYTUNE bytestream",
"miditones [-p] [-lg] [-lp] [-s1] [-tn] <basefilename>",
"miditones [-p] [-lg] [-lp] [-s1] [-tn] [-v] <basefilename>",
" -p parse only, don't generate bytestream", " -p parse only, don't generate bytestream",
" -lp log input parsing", " -lp log input parsing",
" -lg log output generation", " -lg log output generation",
" -b binary file output instead of C source text", " -b binary file output instead of C source text",
" -cn mask for which tracks to process, e.g. -c3 for only 0 and 1", " -cn mask for which tracks to process, e.g. -c3 for only 0 and 1",
" -kn key shift in chromatic notes, positive or negative", " -kn key shift in chromatic notes, positive or negative",
" -v include velocity data in play note commands",
"input file: <basefilename>.mid", "input file: <basefilename>.mid",
"output file: <basefilename>.bin or .c", "output file: <basefilename>.bin or .c",
"log file: <basefilename>.log", "log file: <basefilename>.log",
} }





/**************** utility routines **********************/ /**************** utility routines **********************/


size_t strlcat (char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return (dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return (dlen + (s - src)); /* count does not include NUL */
}


size_t strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0') break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return (s - src - 1); /* count does not include NUL */
/* safe string copy */
size_t miditones_strlcpy(char *dst, const char *src, size_t siz) {
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0)
{
while (--n != 0)
{
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0)
{
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return (s - src - 1); /* count does not include NUL */
} }



/* safe string concatenation */

size_t miditones_strlcat(char *dst, const char *src, size_t siz) {
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return (dlen + strlen(s));
while (*s != '\0')
{
if (n != 1)
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return (dlen + (s - src)); /* count does not include NUL */
}


/* match a constant character sequence */ /* match a constant character sequence */




/* check that we have a specified number of bytes left in the buffer */ /* check that we have a specified number of bytes left in the buffer */


void chk_bufdata(unsigned char *ptr, int len) {
if (ptr + len - buffer > buflen) midi_error("data missing", ptr);
void chk_bufdata(unsigned char *ptr, unsigned long int len) {
if ((unsigned)(ptr + len - buffer) > buflen) midi_error("data missing", ptr);
} }






chk_bufdata(hdrptr, sizeof(struct midi_header)); chk_bufdata(hdrptr, sizeof(struct midi_header));
hdr = (struct midi_header *) hdrptr; hdr = (struct midi_header *) hdrptr;
if (!charcmp((char *)(hdr->MThd),"MThd")) midi_error("Missing 'MThd'", hdrptr);
if (!charcmp((char*)hdr->MThd,"MThd")) midi_error("Missing 'MThd'", hdrptr);


num_tracks = rev_short(hdr->number_of_tracks); num_tracks = rev_short(hdr->number_of_tracks);


unsigned long int delta_time; unsigned long int delta_time;
int event, chan; int event, chan;
int i; int i;
int note, velocity; // , parm;
int note, velocity;
int meta_cmd, meta_length; int meta_cmd, meta_length;
unsigned long int sysex_length; unsigned long int sysex_length;
struct track_status *t; struct track_status *t;
delta_time = get_varlen(&t->trkptr); delta_time = get_varlen(&t->trkptr);
if (logparse) { if (logparse) {
fprintf (logfile, "trk %d ", tracknum); fprintf (logfile, "trk %d ", tracknum);
fprintf (logfile, delta_time ? "delta time %4ld, " : " ", delta_time);
if (delta_time) {
fprintf (logfile, "delta time %4ld, ", delta_time);
} else {
fprintf (logfile, " ");
}
} }
t->time += delta_time; t->time += delta_time;


#define MAXPATH 120 #define MAXPATH 120
char filename[MAXPATH]; char filename[MAXPATH];


//int i;
int tracknum; int tracknum;
int earliest_tracknum; int earliest_tracknum;
unsigned long earliest_time; unsigned long earliest_time;
int notes_skipped = 0; int notes_skipped = 0;


printf("MIDITONES V%s, (C) 2011 Len Shustek\n", VERSION);
printf("MIDITONES V%s, (C) 2011,2015,2016 Len Shustek\n", VERSION);
printf("See the source code for license information.\n\n"); printf("See the source code for license information.\n\n");
if (argc == 1) { /* no arguments */ if (argc == 1) { /* no arguments */
SayUsage(argv[0]); SayUsage(argv[0]);
/* Open the log file */ /* Open the log file */


if (logparse || loggen) { if (logparse || loggen) {
strlcpy(filename, filebasename, MAXPATH);
strlcat(filename, ".log", MAXPATH);
miditones_strlcpy(filename, filebasename, MAXPATH);
miditones_strlcat(filename, ".log", MAXPATH);
logfile = fopen(filename, "w"); logfile = fopen(filename, "w");
if (!logfile) { if (!logfile) {
fprintf(stderr, "Unable to open log file %s", filename); fprintf(stderr, "Unable to open log file %s", filename);


/* Open the input file */ /* Open the input file */


strlcpy(filename, filebasename, MAXPATH);
strlcat(filename, ".mid", MAXPATH);
miditones_strlcpy(filename, filebasename, MAXPATH);
miditones_strlcat(filename, ".mid", MAXPATH);
infile = fopen(filename, "rb"); infile = fopen(filename, "rb");
if (!infile) { if (!infile) {
fprintf(stderr, "Unable to open input file %s", filename); fprintf(stderr, "Unable to open input file %s", filename);
/* Create the output file */ /* Create the output file */


if (!parseonly) { if (!parseonly) {
strlcpy(filename, filebasename, MAXPATH);
miditones_strlcpy(filename, filebasename, MAXPATH);
if (binaryoutput) { if (binaryoutput) {
strlcat(filename, ".bin", MAXPATH);
miditones_strlcat(filename, ".bin", MAXPATH);
outfile = fopen(filename, "wb"); outfile = fopen(filename, "wb");
} }
else { else {
strlcat(filename, ".c", MAXPATH);
miditones_strlcat(filename, ".c", MAXPATH);
outfile = fopen(filename, "w"); outfile = fopen(filename, "w");
} }
if (!outfile) { if (!outfile) {
} }
if (!binaryoutput) { /* create header of C file that initializes score data */ if (!binaryoutput) { /* create header of C file that initializes score data */
time_t rawtime; time_t rawtime;
//struct tm *ptime;
time (&rawtime); time (&rawtime);
fprintf(outfile, "// Playtune bytestream for file \"%s.mid\" ", filebasename); fprintf(outfile, "// Playtune bytestream for file \"%s.mid\" ", filebasename);
fprintf(outfile, "created by MIDITONES V%s on %s", VERSION, asctime(localtime(&rawtime))); fprintf(outfile, "created by MIDITONES V%s on %s", VERSION, asctime(localtime(&rawtime)));

Loading…
Cancel
Save