Update portsmf to latest r234 commit

This commit is contained in:
Veratil
2020-08-18 19:45:20 -05:00
committed by Kevin Zander
parent 3d8b31039f
commit 76a182bb95
12 changed files with 2529 additions and 1669 deletions

View File

@@ -1,4 +1,5 @@
/* algread_internal.h -- interface between allegro.cpp and allegrord.cpp */
Alg_error alg_read(std::istream &file, Alg_seq_ptr new_seq);
/* algread_internal.h -- interface between allegro.cpp and allegrord.cpp */
Alg_error alg_read(std::istream &file, Alg_seq_ptr new_seq,
double *offset_ptr = NULL);

File diff suppressed because it is too large Load Diff

View File

@@ -46,11 +46,11 @@
// Just as serialization uses ser_buf for output, unserialization uses
// unser_buf for reading. unser_buf is another static member of Alg_track.
#ifndef __ALLEGRO__
#define __ALLEGRO__
#include "debug.h"
#include "lmmsconfig.h"
#ifndef ALLEGRO_H
#define ALLEGRO_H
#include <assert.h>
#include <istream>
#include <ostream>
#define ALG_EPS 0.000001 // epsilon
#define ALG_DEFAULT_BPM 100.0 // default tempo
@@ -67,7 +67,7 @@ char *heapify(const char *s); // put a string on the heap
// the attribute 'tempor' (a real) is stored
// as 'rtempor'. To get the string name, just
// use attribute+1.
typedef char *Alg_attribute;
typedef const char *Alg_attribute;
#define alg_attr_name(a) ((a) + 1)
#define alg_attr_type(a) (*(a))
@@ -79,6 +79,19 @@ public:
maxlen = len = 0;
atoms = NULL;
}
// Note: the code is possibly more correct and faster without the
// following destructor, which will only run after the program takes
// a normal exit. Cleaning up after the program exit slows down the exit,
// and will cause problems if any other destructor tries to reference an
// Alg_atom (which will now be freed). The advantage of this code is
// that Alg_atoms will not be reported as memory leaks by automation
// that doesn't know better. -RBD
virtual ~Alg_atoms() {
for (int i = 0; i < len; i++) {
delete atoms[i];
}
if (atoms) delete [] atoms;
}
// insert/lookup an atttribute
Alg_attribute insert_attribute(Alg_attribute attr);
// insert/lookup attribute by name (without prefixed type)
@@ -86,7 +99,7 @@ public:
private:
long maxlen;
long len;
char **atoms;
Alg_attribute *atoms;
// insert an Attriubute not in table after moving attr to heap
Alg_attribute insert_new(const char *name, char attr_type);
@@ -101,18 +114,24 @@ extern Alg_atoms symbol_table;
// Alg_parameter class
typedef class Alg_parameter {
public:
~Alg_parameter();
// This constructor guarantees that an Alg_parameter can be
// deleted safely without further initialization. It does not
// do anything useful, so it is expected that the creator will
// set attr and store a value in the appropriate union field.
Alg_attribute attr;
union {
double r;// real
char *s; // string
const char *s; // string
long i; // integer
bool l; // logical
char *a; // symbol (atom)
const char *a; // symbol (atom)
}; // anonymous union
Alg_parameter() { attr = "i"; }
~Alg_parameter();
void copy(Alg_parameter *); // copy from another parameter
char attr_type() { return alg_attr_type(attr); }
char *attr_name() { return alg_attr_name(attr); }
const char attr_type() { return alg_attr_type(attr); }
const char *attr_name() { return alg_attr_name(attr); }
void set_attr(Alg_attribute a) { attr = a; }
void show();
} *Alg_parameter_ptr;
@@ -139,15 +158,17 @@ public:
// attribute. If you have already done the symbol table lookup/insert
// you can do these operations faster (in which case we should add
// another set of functions that take attributes as arguments.)
static void insert_real(Alg_parameters **list, char *name, double r);
static void insert_real(Alg_parameters **list, const char *name, double r);
// insert string will copy string to heap
static void insert_string(Alg_parameters **list, char *name, char *s);
static void insert_integer(Alg_parameters **list, char *name, long i);
static void insert_logical(Alg_parameters **list, char *name, bool l);
static void insert_atom(Alg_parameters **list, char *name, char *s);
static void insert_string(Alg_parameters **list, const char *name,
const char *s);
static void insert_integer(Alg_parameters **list, const char *name, long i);
static void insert_logical(Alg_parameters **list, const char *name, bool l);
static void insert_atom(Alg_parameters **list, const char *name,
const char *s);
static Alg_parameters *remove_key(Alg_parameters **list, const char *name);
// find an attribute/value pair
Alg_parameter_ptr find(Alg_attribute *attr);
Alg_parameter_ptr find(Alg_attribute attr);
} *Alg_parameters_ptr;
@@ -198,11 +219,11 @@ public:
// attribute (first argument) must agree in type with the second arg.
// The last letter of the attribute implies the type (see below).
void set_parameter(Alg_parameter_ptr new_parameter);
void set_string_value(char *attr, char *value);
void set_real_value(char *attr, double value);
void set_logical_value(char *attr, bool value);
void set_integer_value(char *attr, long value);
void set_atom_value(char *attr, char *atom);
void set_string_value(const char *attr, const char *value);
void set_real_value(const char *attr, double value);
void set_logical_value(const char *attr, bool value);
void set_integer_value(const char *attr, long value);
void set_atom_value(const char *attr, const char *atom);
// Some note methods. These fail (via assert()) if this is not a note:
//
@@ -222,17 +243,22 @@ public:
// types. Attribute names end with a type designation: 's', 'r', 'l',
// 'i', or 'a'.
//
bool has_attribute(char *attr); // test if note has attribute/value pair
char get_attribute_type(char *attr); // get the associated type:
bool has_attribute(const char *attr); // test if note has attribute/value pair
char get_attribute_type(const char *attr); // get the associated type:
// 's' = string,
// 'r' = real (double), 'l' = logical (bool), 'i' = integer (long),
// 'a' = atom (char *), a unique string stored in Alg_seq
char *get_string_value(char *attr, char *value = NULL); // get the string value
double get_real_value(char *attr, double value = 0.0); // get the real value
bool get_logical_value(char *attr, bool value = false); // get the logical value
long get_integer_value(char *attr, long value = 0); // get the integer value
char *get_atom_value(char *attr, char *value = NULL); // get the atom value
void delete_attribute(char *attr); // delete an attribute/value pair
// get the string value
const char *get_string_value(const char *attr, const char *value = NULL);
// get the real value
double get_real_value(const char *attr, double value = 0.0);
// get the logical value
bool get_logical_value(const char *attr, bool value = false);
// get the integer value
long get_integer_value(const char *attr, long value = 0);
// get the atom value
const char *get_atom_value(const char *attr, const char *value = NULL);
void delete_attribute(const char *attr); // delete an attribute/value pair
// (ignore if no matching attribute/value pair exists)
// Some attribute/value methods. These fail if this is not an update.
@@ -243,13 +269,13 @@ public:
char get_update_type(); // get the update's type: 's' = string,
// 'r' = real (double), 'l' = logical (bool), 'i' = integer (long),
// 'a' = atom (char *), a unique string stored in Alg_seq
char *get_string_value(); // get the update's string value
const char *get_string_value(); // get the update's string value
// Notes: Caller does not own the return value. Do not modify.
// Do not use after underlying Alg_seq is modified.
double get_real_value(); // get the update's real value
bool get_logical_value(); // get the update's logical value
long get_integer_value(); // get the update's integer value
char *get_atom_value(); // get the update's atom value
const char *get_atom_value(); // get the update's atom value
// Notes: Caller does not own the return value. Do not modify.
// The return value's lifetime is forever.
@@ -305,6 +331,9 @@ public:
// creating a new track and adding notes to it. It is *not*
// updated after uninsert(), so use it with care.
double last_note_off;
// initially false, in_use can be used to mark "do not delete". If an
// Alg_events instance is deleted while "in_use", an assertion will fail.
bool in_use;
virtual int length() { return len; }
Alg_event_ptr &operator[](int i) {
assert(i >= 0 && i < len);
@@ -314,10 +343,11 @@ public:
maxlen = len = 0;
events = NULL;
last_note_off = 0;
in_use = false;
}
// destructor deletes the events array, but not the
// events themselves
~Alg_events();
virtual ~Alg_events();
void set_events(Alg_event_ptr *e, long l, long m) {
if (events) delete [] events;
events = e; len = l; maxlen = m; }
@@ -468,8 +498,11 @@ public:
// you want tracks to be in beat units.
void insert_beat(double time, double beat); // add a point to the map
bool insert_tempo(double tempo, double beat); // insert a tempo change
// get the tempo starting at beat
double get_tempo(double beat);
// set the tempo over a region
bool set_tempo(double tempo, double start_beat, double end_beat);
bool stretch_region(double b0, double b1, double dur);
void cut(double start, double len, bool units_are_seconds);
void trim(double start, double end, bool units_are_seconds);
void paste(double start, Alg_track *tr);
@@ -488,20 +521,76 @@ public:
} *Alg_time_map_ptr;
typedef class Serial_buffer {
private:
// Serial_buffer is an abstract class with common elements of
// Serial_read_buffer and Serial_write_buffer
class Serial_buffer {
protected:
char *buffer;
char *ptr;
long len;
public:
public:
Serial_buffer() {
buffer = NULL;
ptr = NULL;
len = 0;
}
void init_for_write() { ptr = buffer; }
virtual ~Serial_buffer() { }
long get_posn() { return (long) (ptr - buffer); }
long get_len() { return len; }
};
typedef class Serial_read_buffer : public Serial_buffer {
public:
// note that a Serial_read_buffer is initialized for reading by
// setting buffer, but it is not the Serial_read_buffer's responsibility
// to delete the buffer (owner might want to reuse it), so the destructor
// does nothing.
virtual ~Serial_read_buffer() { }
#if defined(_WIN32)
#pragma warning(disable: 546) // cast to int is OK, we only want low 7 bits
#pragma warning(disable: 4311) // type cast pointer to long warning
#endif
void get_pad() { while (((long) ptr) & 7) ptr++; }
#if defined(_WIN32)
#pragma warning(default: 4311 546)
#endif
// Prepare to read n bytes from buf. The caller must manage buf: it is
// valid until reading is finished, and it is caller's responsibility
// to free buf when it is no longer needed.
void init_for_read(void *buf, long n) {
buffer = (char *) buf;
ptr = (char *) buf;
len = n;
}
char get_char() { return *ptr++; }
void unget_chars(int n) { ptr -= n; } // undo n get_char() calls
long get_int32() { long i = *((long *) ptr); ptr += 4; return i; }
float get_float() { float f = *((float *) ptr); ptr += 4; return f; }
double get_double() { double d = *((double *) ptr); ptr += sizeof(double);
return d; }
const char *get_string() { char *s = ptr; char *fence = buffer + len;
assert(ptr < fence);
while (*ptr++) assert(ptr < fence);
get_pad();
return s; }
void check_input_buffer(long needed) {
assert(get_posn() + needed <= len); }
} *Serial_read_buffer_ptr;
typedef class Serial_write_buffer: public Serial_buffer {
public:
// Note: allegro.cpp declares one static instance of Serial_buffer to
// reduce large memory (re)allocations when serializing tracks for UNDO.
// This destructor will only run when the program exits, which will only
// add overhead to the exit process, but it will eliminate an incorrect
// report of memory leakage from automation that doesn't know better. -RBD
virtual ~Serial_write_buffer() {
if (buffer) delete [] buffer;
}
void init_for_write() { ptr = buffer; }
// store_long writes a long at a given offset
void store_long(long offset, long value) {
assert(offset <= get_posn() - 4);
@@ -509,20 +598,33 @@ public:
*loc = value;
}
void check_buffer(long needed);
void set_string(char *s) {
void set_string(const char *s) {
char *fence = buffer + len;
assert(ptr < fence);
// two brackets surpress a g++ warning, because this is an
// assignment operator inside a test.
while ((*ptr++ = *s++)) assert(ptr < fence);
// assert((char *)(((long) (ptr + 7)) & ~7) <= fence);
// 4311 is type cast pointer to long warning
// 4312 is type cast long to pointer warning
#if defined(_WIN32)
#pragma warning(disable: 4311 4312)
#endif
assert((char *)(((long) (ptr + 7)) & ~7) <= fence);
#if defined(_WIN32)
#pragma warning(default: 4311 4312)
#endif
pad(); }
void set_int32(long v) { *((long *) ptr) = v; ptr += 4; }
void set_double(double v) { *((double *) ptr) = v; ptr += 8; }
void set_float(float v) { *((float *) ptr) = v; ptr += 4; }
void set_char(char v) { *ptr++ = v; }
#ifdef LMMS_BUILD_WIN64
void pad() { while (((long long) ptr) & 7) set_char(0); }
#else
#if defined(_WIN32)
#pragma warning(disable: 546) // cast to int is OK, we only want low 7 bits
#pragma warning(disable: 4311) // type cast pointer to long warning
#endif
void pad() { while (((long) ptr) & 7) set_char(0); }
#if defined(_WIN32)
#pragma warning(default: 4311 546)
#endif
void *to_heap(long *len) {
*len = get_posn();
@@ -530,29 +632,7 @@ public:
memcpy(newbuf, buffer, *len);
return newbuf;
}
void init_for_read(void *buf, long n) {
buffer = (char *) buf;
ptr = (char *) buf;
len = n;
}
char get_char() { return *ptr++; }
long get_int32() { long i = *((long *) ptr); ptr += 4; return i; }
float get_float() { float f = *((float *) ptr); ptr += 4; return f; }
double get_double() { double d = *((double *) ptr); ptr += sizeof(double);
return d; }
char *get_string() { char *s = ptr; char *fence = buffer + len;
assert(ptr < fence);
while (*ptr++) assert(ptr < fence);
get_pad();
return s; }
#ifdef LMMS_BUILD_WIN64
void get_pad() { while (((long long) ptr) & 7) ptr++; }
#else
void get_pad() { while (((long) ptr) & 7) ptr++; }
#endif
void check_input_buffer(long needed) {
assert(get_posn() + needed <= len); }
} *Serial_buffer_ptr;
} *Serial_write_buffer_ptr;
typedef class Alg_seq *Alg_seq_ptr;
@@ -564,7 +644,8 @@ protected:
long get_int32(char **p, long *b);
double get_double(char **p, long *b);
float get_float(char **p, long *b);
static Serial_buffer ser_buf;
static Serial_read_buffer ser_read_buf;
static Serial_write_buffer ser_write_buf;
void serialize_parameter(Alg_parameter *parm);
// *buffer_ptr points to binary data, bytes_ptr points to how many
// bytes have been used so far, len is length of binary data
@@ -587,7 +668,8 @@ public:
// copy constructor: event_list is copied, map is installed and referenced
Alg_track(Alg_event_list_ref event_list, Alg_time_map_ptr map,
bool units_are_seconds);
virtual ~Alg_track() { set_time_map(NULL); }
virtual ~Alg_track() { // note: do not call set_time_map(NULL)!
if (time_map) time_map->dereference(); time_map = NULL; }
// Returns a buffer containing a serialization of the
// file. It will be an ASCII representation unless text is true.
@@ -726,6 +808,7 @@ public:
virtual Alg_event_list *find(double t, double len, bool all,
long channel_mask, long event_type_mask);
virtual void set_in_use(bool flag) { in_use = flag; }
//
// MIDI playback
//
@@ -785,11 +868,15 @@ public:
void show();
long length() { return len; }
int find_beat(double beat);
void insert(double beat, double num, double den);
void cut(double start, double end); // remove from start to end
// get the number of beats per measure starting at beat
double get_bar_len(double beat);
void insert(double beat, double num, double den, bool force = false);
void cut(double start, double end, double dur); // remove from start to end
void trim(double start, double end); // retain just start to end
void paste(double start, Alg_seq *seq);
void insert_beats(double beat, double len); // insert len beats at beat
// find the nearest beat (see Alg_seq::nearest_beat) to beat
double nearest_beat(double beat);
};
@@ -816,26 +903,103 @@ public:
void append(Alg_track_ptr track);
void add_track(int track_num, Alg_time_map_ptr time_map, bool seconds);
void reset();
void set_in_use(bool flag); // handy to set in_use flag on all tracks
} *Alg_tracks_ptr;
typedef enum {
alg_no_error = 0, // no error reading Allegro or MIDI file
alg_error_open = -800, // could not open Allegro or MIDI file
alg_error_syntax // something found in the file that could not be parsed;
// generally you should ignore syntax errors or look at the printed error messages
// because there are some things in standard midi files that we do not handle;
// (maybe we should only set alg_error_syntax when there is a real problem with
// the file as opposed to when there is some warning message for the user)
alg_error_syntax // something found in the file that could not be parsed;
// generally you should ignore syntax errors or look at the printed error
// messages because there are some things in standard midi files that we do
// not handle; (maybe we should only set alg_error_syntax when there is a
// real problem with the file as opposed to when there is some warning
// message for the user)
} Alg_error;
typedef struct Alg_pending_event {
void *cookie; // client-provided sequence identifier
Alg_events *events; // the array of events
long index; // offset of this event
bool note_on; // is this a note-on or a note-off (if applicable)?
double offset; // time offset for events
double time; // time for this event
} *Alg_pending_event_ptr;
typedef class Alg_iterator {
private:
long maxlen;
void expand();
void expand_to(int new_max);
long len;
Alg_seq_ptr seq;
Alg_pending_event *pending_events;
// the next four fields are mainly for request_note_off()
Alg_events_ptr events_ptr; // remembers events containing current event
long index; // remembers index of current event
void *cookie; // remembers the cookie associated with next event
double offset;
void show();
bool earlier(int i, int j);
void insert(Alg_events_ptr events, long index, bool note_on,
void *cookie, double offset);
// returns the info on the next pending event in the priority queue
bool remove_next(Alg_events_ptr &events, long &index, bool &note_on,
void *&cookie, double &offset, double &time);
public:
bool note_off_flag; // remembers if we are iterating over note-off
// events as well as note-on and update events
long length() { return len; }
Alg_iterator(Alg_seq_ptr s, bool note_off) {
seq = s;
note_off_flag = note_off;
maxlen = len = 0;
pending_events = NULL;
}
// Normally, iteration is over the events in the one sequence used
// to instatiate the iterator (see above), but with this method, you
// can add more sequences to the iteration. Events are returned in
// time order, so effectively sequence events are merged.
// The optional offset is added to each event time of sequence s
// before merging/sorting. You should call begin_seq() for each
// sequence to be included in the iteration unless you call begin()
// (see below).
void begin_seq(Alg_seq_ptr s, void *cookie = NULL, double offset = 0.0);
~Alg_iterator();
// Prepare to enumerate events in order. If note_off_flag is true, then
// iteration_next will merge note-off events into the sequence. If you
// call begin(), you should not normally call begin_seq(). See above.
void begin(void *cookie = NULL) { begin_seq(seq, cookie); }
// return next event (or NULL). If iteration_begin was called with
// note_off_flag = true, and if note_on is not NULL, then *note_on
// is set to true when the result value represents a note-on or update.
// (With note_off_flag, each Alg_note event is returned twice, once
// at the note-on time, with *note_on == true, and once at the note-off
// time, with *note_on == false. If a cookie_ptr is passed, then the
// cookie corresponding to the event is stored at that address
// If end_time is 0, iterate through the entire sequence, but if
// end_time is non_zero, stop iterating at the last event before end_time
Alg_event_ptr next(bool *note_on = NULL, void **cookie_ptr = NULL,
double *offset_ptr = NULL, double end_time = 0);
// Sometimes, the caller wants to receive note-off events for a subset
// of the notes, typically the notes that are played and need to be
// turned off. In this case, when a note is turned on, the client
// should call request_note_off(). This will insert a note-off into
// the queue for the most recent note returned by next().
void request_note_off();
void end(); // clean up after enumerating events
} *Alg_iterator_ptr;
// An Alg_seq is an array of Alg_events, each a sequence of Alg_event,
// with a tempo map and a sequence of time signatures
//
typedef class Alg_seq : public Alg_track {
protected:
long *current; // array of indexes used by iteration methods
Alg_iterator_ptr pending; // iterator used internally by Alg_seq methods
void serialize_seq();
Alg_error error; // error code set by file readers
// an internal function used for writing Allegro track names
@@ -860,9 +1024,11 @@ public:
Alg_seq(Alg_track_ref track) { seq_from_track(track); }
Alg_seq(Alg_track_ptr track) { seq_from_track(*track); }
void seq_from_track(Alg_track_ref tr);
Alg_seq(std::istream &file, bool smf); // create from file
Alg_seq(const char *filename, bool smf); // create from filename
~Alg_seq();
// create from file:
Alg_seq(std::istream &file, bool smf, double *offset_ptr = NULL);
// create from filename
Alg_seq(const char *filename, bool smf, double *offset_ptr = NULL);
virtual ~Alg_seq();
int get_read_error() { return error; }
void serialize(void **buffer, long *bytes);
void copy_time_sigs_to(Alg_seq *dest); // a utility function
@@ -874,10 +1040,10 @@ public:
void unserialize_seq();
// write an ascii representation to file
void write(std::ostream &file, bool in_secs);
void write(std::ostream &file, bool in_secs, double offset = 0.0);
// returns true on success
bool write(const char *filename);
void smf_write(std::ofstream &file);
bool write(const char *filename, double offset = 0.0);
void smf_write(std::ostream &file);
bool smf_write(const char *filename);
// Returns the number of tracks
@@ -917,23 +1083,34 @@ public:
// find index of first score event after time
long seek_time(double time, int track_num);
bool insert_beat(double time, double beat);
// return the time of the beat nearest to time, also returns beat
// number through beat. This will correspond to an integer number
// of beats from the nearest previous time signature or 0.0, but
// since time signatures need not be on integer beat boundaries
// the beat location may not be on an integer beat (beat locations
// are measured from the beginning which is beat 0.
double nearest_beat_time(double time, double *beat);
// warning: insert_tempo may change representation from seconds to beats
bool insert_tempo(double bpm, double beat);
// change the duration from b0 to b1 (beats) to dur (seconds) by
// scaling the intervening tempos
bool stretch_region(double b0, double b1, double dur);
// add_event takes a pointer to an event on the heap. The event is not
// copied, and this Alg_seq becomes the owner and freer of the event.
void add_event(Alg_event_ptr event, int track_num);
void add(Alg_event_ptr event) { assert(false); } // call add_event instead
// warning: set_tempo may change representation from seconds to beats
// get the tempo starting at beat
double get_tempo(double beat);
bool set_tempo(double bpm, double start_beat, double end_beat);
// get the bar length in beats starting at beat
double get_bar_len(double beat);
void set_time_sig(double beat, double num, double den);
void beat_to_measure(double beat, long *measure, double *m_beat,
double *num, double *den);
// void set_events(Alg_event_ptr *events, long len, long max);
void merge_tracks(); // move all track data into one track
void iteration_begin(); // prepare to enumerate events in order
Alg_event_ptr iteration_next(); // return next event (or NULL)
void iteration_end(); // clean up after enumerating events
void set_in_use(bool flag); // set in_use flag on all tracks
} *Alg_seq_ptr, &Alg_seq_ref;

File diff suppressed because it is too large Load Diff

View File

@@ -1,445 +1,455 @@
// midifile reader
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "debug.h"
#include <string>
#include <fstream>
#include "allegro.h"
#include "algsmfrd_internal.h"
#include "mfmidi.h"
#include "trace.h"
using namespace std;
typedef class Alg_pending {
public:
Alg_note_ptr note;
class Alg_pending *next;
Alg_pending(Alg_note_ptr n, class Alg_pending *list) {
note = n; next = list; }
} *Alg_pending_ptr;
class Alg_midifile_reader: public Midifile_reader {
public:
istream *file;
Alg_seq_ptr seq;
int divisions;
Alg_pending_ptr pending;
Alg_track_ptr track;
int track_number; // the number of the (current) track
// chan is actual_channel + channel_offset_per_track * track_num +
// channel_offset_per_track * port
long channel_offset_per_track; // used to encode track number into channel
// default is 0, set this to 0 to merge all tracks to 16 channels
long channel_offset_per_port; // used to encode port number into channel
// default is 16, set to 0 to ignore port prefix meta events
// while reading, this is channel_offset_per_track * track_num
int channel_offset;
Alg_midifile_reader(istream &f, Alg_seq_ptr new_seq) {
file = &f;
pending = NULL;
seq = new_seq;
channel_offset_per_track = 0;
channel_offset_per_port = 16;
track_number = -1; // no tracks started yet, 1st will be #0
meta_channel = -1;
port = 0;
}
// delete destroys the seq member as well, so set it to NULL if you
// copied the pointer elsewhere
~Alg_midifile_reader();
// the following is used to load the Alg_seq from the file:
bool parse();
void set_nomerge(bool flag) { Mf_nomerge = flag; }
void set_skipinit(bool flag) { Mf_skipinit = flag; }
long get_currtime() { return Mf_currtime; }
protected:
int meta_channel; // the channel for meta events, set by MIDI chan prefix
int port; // value from the portprefix meta event
double get_time();
void update(int chan, int key, Alg_parameter_ptr param);
void *Mf_malloc(size_t size) { return malloc(size); }
void Mf_free(void *obj, size_t size) { free(obj); }
/* Methods to be called while processing the MIDI file. */
void Mf_starttrack();
void Mf_endtrack();
int Mf_getc();
void Mf_chanprefix(int chan);
void Mf_portprefix(int port);
void Mf_eot();
void Mf_error(const char *);
void Mf_header(int,int,int);
void Mf_on(int,int,int);
void Mf_off(int,int,int);
void Mf_pressure(int,int,int);
void Mf_controller(int,int,int);
void Mf_pitchbend(int,int,int);
void Mf_program(int,int);
void Mf_chanpressure(int,int);
void binary_msg(int len, char *msg, const char *attr_string);
void Mf_sysex(int,char*);
void Mf_arbitrary(int,char*);
void Mf_metamisc(int,int,char*);
void Mf_seqnum(int);
void Mf_smpte(int,int,int,int,int);
void Mf_timesig(int,int,int,int);
void Mf_tempo(int);
void Mf_keysig(int,int);
void Mf_sqspecific(int,char*);
void Mf_text(int,int,char*);
};
Alg_midifile_reader::~Alg_midifile_reader()
{
while (pending) {
Alg_pending_ptr to_be_freed = pending;
pending = pending->next;
delete to_be_freed;
}
finalize(); // free Mf reader memory
}
bool Alg_midifile_reader::parse()
{
channel_offset = 0;
seq->convert_to_beats();
midifile();
seq->set_real_dur(seq->get_time_map()->beat_to_time(seq->get_beat_dur()));
return midifile_error != 0;
}
void Alg_midifile_reader::Mf_starttrack()
{
// printf("starting new track\n");
// create a new track that will share the sequence time map
// since time is in beats, the seconds parameter is false
track_number++;
seq->add_track(track_number); // make sure track exists
track = seq->track(track_number); // keep pointer to current track
meta_channel = -1;
port = 0;
}
void Alg_midifile_reader::Mf_endtrack()
{
// note: track is already part of seq, so do not add it here
// printf("finished track, length %d number %d\n", track->len, track_num / 100);
channel_offset += seq->channel_offset_per_track;
track = NULL;
double now = get_time();
if (seq->get_beat_dur() < now) seq->set_beat_dur(now);
meta_channel = -1;
port = 0;
}
int Alg_midifile_reader::Mf_getc()
{
return file->get();
}
void Alg_midifile_reader::Mf_chanprefix(int chan)
{
meta_channel = chan;
}
void Alg_midifile_reader::Mf_portprefix(int p)
{
port = p;
}
void Alg_midifile_reader::Mf_eot()
{
meta_channel = -1;
port = 0;
}
void Alg_midifile_reader::Mf_error(const char *msg)
{
fprintf(stdout, "Midifile reader error: %s\n", msg);
}
void Alg_midifile_reader::Mf_header(int format, int ntrks, int division)
{
if (format > 1) {
char msg[80];
sprintf(msg, "file format %d not implemented", format);
Mf_error(msg);
}
divisions = division;
}
double Alg_midifile_reader::get_time()
{
double beat = ((double) get_currtime()) / divisions;
return beat;
}
void Alg_midifile_reader::Mf_on(int chan, int key, int vel)
{
assert(!seq->get_units_are_seconds());
if (vel == 0) {
Mf_off(chan, key, vel);
return;
}
Alg_note_ptr note = new Alg_note();
pending = new Alg_pending(note, pending);
/* trace("on: %d at %g\n", key, get_time()); */
note->time = get_time();
note->chan = chan + channel_offset + port * channel_offset_per_port;
note->dur = 0;
note->set_identifier(key);
note->pitch = (float) key;
note->loud = (float) vel;
track->append(note);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_off(int chan, int key, int vel)
{
double time = get_time();
Alg_pending_ptr *p = &pending;
while (*p) {
if ((*p)->note->get_identifier() == key &&
(*p)->note->chan ==
chan + channel_offset + port * channel_offset_per_port) {
(*p)->note->dur = time - (*p)->note->time;
// trace("updated %d dur %g\n", (*p)->note->key, (*p)->note->dur);
Alg_pending_ptr to_be_freed = *p;
*p = to_be_freed->next;
delete to_be_freed;
} else {
p = &((*p)->next);
}
}
meta_channel = -1;
}
void Alg_midifile_reader::update(int chan, int key, Alg_parameter_ptr param)
{
Alg_update_ptr update = new Alg_update;
update->time = get_time();
update->chan = chan;
if (chan != -1) {
update->chan = chan + channel_offset + port * channel_offset_per_port;
}
update->set_identifier(key);
update->parameter = *param;
// prevent the destructor from destroying the string twice!
// the new Update takes the string from param
if (param->attr_type() == 's') param->s = NULL;
track->append(update);
}
void Alg_midifile_reader::Mf_pressure(int chan, int key, int val)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("pressurer"));
parameter.r = val / 127.0;
update(chan, key, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_controller(int chan, int control, int val)
{
Alg_parameter parameter;
char name[32];
sprintf(name, "control%dr", control);
parameter.set_attr(symbol_table.insert_string(name));
parameter.r = val / 127.0;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_pitchbend(int chan, int c1, int c2)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("bendr"));
parameter.r = ((c2 << 7) + c1) / 8192.0 - 1.0;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_program(int chan, int program)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("programi"));
parameter.i = program;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_chanpressure(int chan, int val)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("pressurer"));
parameter.r = val / 127.0;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::binary_msg(int len, char *msg,
const char *attr_string)
{
Alg_parameter parameter;
char *hexstr = new char[len * 2 + 1];
for (int i = 0; i < len; i++) {
sprintf(hexstr + 2 * i, "%02x", (0xFF & msg[i]));
}
parameter.s = hexstr;
parameter.set_attr(symbol_table.insert_string(attr_string));
update(meta_channel, -1, &parameter);
}
void Alg_midifile_reader::Mf_sysex(int len, char *msg)
{
// sysex messages become updates with attribute sysexs and a hex string
binary_msg(len, msg, "sysexs");
}
void Alg_midifile_reader::Mf_arbitrary(int len, char *msg)
{
Mf_error("arbitrary data ignored");
}
void Alg_midifile_reader::Mf_metamisc(int type, int len, char *msg)
{
char text[128];
sprintf(text, "metamsic data, type 0x%x, ignored", type);
Mf_error(text);
}
void Alg_midifile_reader::Mf_seqnum(int n)
{
Mf_error("seqnum data ignored");
}
static const char *fpsstr[4] = {"24", "25", "29.97", "30"};
void Alg_midifile_reader::Mf_smpte(int hours, int mins, int secs,
int frames, int subframes)
{
// string will look like "24fps:01h:27m:07s:19.00f"
// 30fps (drop frame) is notated as "29.97fps"
char text[32];
int fps = (hours >> 6) & 3;
hours &= 0x1F;
sprintf(text, "%sfps:%02dh:%02dm:%02ds:%02d.%02df",
fpsstr[fps], hours, mins, secs, frames, subframes);
Alg_parameter smpteoffset;
smpteoffset.s = heapify(text);
smpteoffset.set_attr(symbol_table.insert_string("smpteoffsets"));
update(meta_channel, -1, &smpteoffset);
// Mf_error("SMPTE data ignored");
}
void Alg_midifile_reader::Mf_timesig(int i1, int i2, int i3, int i4)
{
seq->set_time_sig(get_currtime() / divisions, i1, 1 << i2);
}
void Alg_midifile_reader::Mf_tempo(int tempo)
{
double beat = get_currtime();
beat = beat / divisions; // convert to quarters
// 6000000 us/min / n us/beat => beat / min
double bpm = 60000000.0 / tempo;
seq->insert_tempo(bpm, beat);
}
void Alg_midifile_reader::Mf_keysig(int key, int mode)
{
Alg_parameter key_parm;
key_parm.set_attr(symbol_table.insert_string("keysigi"));
// use 0 for C major, 1 for G, -1 for F, etc., that is,
// the number of sharps, where flats are negative sharps
key_parm.i = key; //<<<---- fix this
// use -1 to mean "all channels"
update(meta_channel, -1, &key_parm);
Alg_parameter mode_parm;
mode_parm.set_attr(symbol_table.insert_string("modea"));
mode_parm.a = (mode == 0 ? symbol_table.insert_string("major") :
symbol_table.insert_string("minor"));
update(meta_channel, -1, &mode_parm);
}
void Alg_midifile_reader::Mf_sqspecific(int len, char *msg)
{
// sequencer specific messages become updates with attribute sqspecifics
// and a hex string for the value
binary_msg(len, msg, "sqspecifics");
}
char *heapify2(int len, char *s)
{
char *h = new char[len + 1];
memcpy(h, s, len);
h[len] = 0;
return h;
}
void Alg_midifile_reader::Mf_text(int type, int len, char *msg)
{
Alg_parameter text;
text.s = heapify2(len, msg);
const char *attr = "miscs";
if (type == 1) attr = "texts";
else if (type == 2) attr = "copyrights";
else if (type == 3)
attr = (track_number == 0 ? "seqnames" : "tracknames");
else if (type == 4) attr = "instruments";
else if (type == 5) attr = "lyrics";
else if (type == 6) attr = "markers";
else if (type == 7) attr = "cues";
text.set_attr(symbol_table.insert_string(attr));
update(meta_channel, -1, &text);
}
// parse file into a seq.
Alg_error alg_smf_read(istream &file, Alg_seq_ptr new_seq)
{
assert(new_seq);
Alg_midifile_reader ar(file, new_seq);
bool err = ar.parse();
ar.seq->set_real_dur(ar.seq->get_time_map()->
beat_to_time(ar.seq->get_beat_dur()));
return (err ? alg_error_syntax : alg_no_error);
}
// midifile reader
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "assert.h"
#include <string>
#include <fstream>
#include "allegro.h"
#include "algsmfrd_internal.h"
#include "mfmidi.h"
#include "trace.h"
using namespace std;
typedef class Alg_note_list {
public:
Alg_note_ptr note;
class Alg_note_list *next;
Alg_note_list(Alg_note_ptr n, class Alg_note_list *list) {
note = n; next = list; }
} *Alg_note_list_ptr;
class Alg_midifile_reader: public Midifile_reader {
public:
istream *file;
Alg_seq_ptr seq;
int divisions;
Alg_note_list_ptr note_list;
Alg_track_ptr track;
int track_number; // the number of the (current) track
// chan is actual_channel + channel_offset_per_track * track_num +
// channel_offset_per_track * port
long channel_offset_per_track; // used to encode track number into channel
// default is 0, set this to 0 to merge all tracks to 16 channels
long channel_offset_per_port; // used to encode port number into channel
// default is 16, set to 0 to ignore port prefix meta events
// while reading, this is channel_offset_per_track * track_num
int channel_offset;
Alg_midifile_reader(istream &f, Alg_seq_ptr new_seq) {
file = &f;
note_list = NULL;
seq = new_seq;
channel_offset_per_track = 0;
channel_offset_per_port = 16;
track_number = -1; // no tracks started yet, 1st will be #0
meta_channel = -1;
port = 0;
}
// delete destroys the seq member as well, so set it to NULL if you
// copied the pointer elsewhere
~Alg_midifile_reader();
// the following is used to load the Alg_seq from the file:
bool parse();
void set_nomerge(bool flag) { Mf_nomerge = flag; }
void set_skipinit(bool flag) { Mf_skipinit = flag; }
long get_currtime() { return Mf_currtime; }
protected:
int meta_channel; // the channel for meta events, set by MIDI chan prefix
int port; // value from the portprefix meta event
double get_time();
void update(int chan, int key, Alg_parameter_ptr param);
void *Mf_malloc(size_t size) { return malloc(size); }
void Mf_free(void *obj, size_t size) { free(obj); }
/* Methods to be called while processing the MIDI file. */
void Mf_starttrack();
void Mf_endtrack();
int Mf_getc();
void Mf_chanprefix(int chan);
void Mf_portprefix(int port);
void Mf_eot();
void Mf_error(char *);
void Mf_header(int,int,int);
void Mf_on(int,int,int);
void Mf_off(int,int,int);
void Mf_pressure(int,int,int);
void Mf_controller(int,int,int);
void Mf_pitchbend(int,int,int);
void Mf_program(int,int);
void Mf_chanpressure(int,int);
void binary_msg(int len, unsigned char *msg, const char *attr_string);
void Mf_sysex(int,unsigned char*);
void Mf_arbitrary(int,unsigned char*);
void Mf_metamisc(int,int,unsigned char*);
void Mf_seqnum(int);
void Mf_smpte(int,int,int,int,int);
void Mf_timesig(int,int,int,int);
void Mf_tempo(int);
void Mf_keysig(int,int);
void Mf_sqspecific(int,unsigned char*);
void Mf_text(int,int,unsigned char*);
};
Alg_midifile_reader::~Alg_midifile_reader()
{
while (note_list) {
Alg_note_list_ptr to_be_freed = note_list;
note_list = note_list->next;
delete to_be_freed;
}
finalize(); // free Mf reader memory
}
bool Alg_midifile_reader::parse()
{
channel_offset = 0;
seq->convert_to_beats();
midifile();
seq->set_real_dur(seq->get_time_map()->beat_to_time(seq->get_beat_dur()));
return midifile_error != 0;
}
void Alg_midifile_reader::Mf_starttrack()
{
// printf("starting new track\n");
// create a new track that will share the sequence time map
// since time is in beats, the seconds parameter is false
track_number++;
seq->add_track(track_number); // make sure track exists
track = seq->track(track_number); // keep pointer to current track
meta_channel = -1;
port = 0;
}
void Alg_midifile_reader::Mf_endtrack()
{
// note: track is already part of seq, so do not add it here
// printf("finished track, length %d number %d\n", track->len, track_num / 100);
channel_offset += seq->channel_offset_per_track;
track = NULL;
double now = get_time();
if (seq->get_beat_dur() < now) seq->set_beat_dur(now);
meta_channel = -1;
port = 0;
}
int Alg_midifile_reader::Mf_getc()
{
return file->get();
}
void Alg_midifile_reader::Mf_chanprefix(int chan)
{
meta_channel = chan;
}
void Alg_midifile_reader::Mf_portprefix(int p)
{
port = p;
}
void Alg_midifile_reader::Mf_eot()
{
meta_channel = -1;
port = 0;
}
void Alg_midifile_reader::Mf_error(char *msg)
{
fprintf(stdout, "Midifile reader error: %s\n", msg);
}
void Alg_midifile_reader::Mf_header(int format, int ntrks, int division)
{
if (format > 1) {
char msg[80];
#pragma warning(disable: 4996) // msg is long enough
sprintf(msg, "file format %d not implemented", format);
#pragma warning(default: 4996)
Mf_error(msg);
}
divisions = division;
}
double Alg_midifile_reader::get_time()
{
double beat = ((double) get_currtime()) / divisions;
return beat;
}
void Alg_midifile_reader::Mf_on(int chan, int key, int vel)
{
assert(!seq->get_units_are_seconds());
if (vel == 0) {
Mf_off(chan, key, vel);
return;
}
Alg_note_ptr note = new Alg_note();
note_list = new Alg_note_list(note, note_list);
/* trace("on: %d at %g\n", key, get_time()); */
note->time = get_time();
note->chan = chan + channel_offset + port * channel_offset_per_port;
note->dur = 0;
note->set_identifier(key);
note->pitch = (float) key;
note->loud = (float) vel;
track->append(note);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_off(int chan, int key, int vel)
{
double time = get_time();
Alg_note_list_ptr *p = &note_list;
while (*p) {
if ((*p)->note->get_identifier() == key &&
(*p)->note->chan ==
chan + channel_offset + port * channel_offset_per_port) {
(*p)->note->dur = time - (*p)->note->time;
// trace("updated %d dur %g\n", (*p)->note->key, (*p)->note->dur);
Alg_note_list_ptr to_be_freed = *p;
*p = to_be_freed->next;
delete to_be_freed;
} else {
p = &((*p)->next);
}
}
meta_channel = -1;
}
void Alg_midifile_reader::update(int chan, int key, Alg_parameter_ptr param)
{
Alg_update_ptr update = new Alg_update;
update->time = get_time();
update->chan = chan;
if (chan != -1) {
update->chan = chan + channel_offset + port * channel_offset_per_port;
}
update->set_identifier(key);
update->parameter = *param;
// prevent the destructor from destroying the string twice!
// the new Update takes the string from param
if (param->attr_type() == 's') param->s = NULL;
track->append(update);
}
void Alg_midifile_reader::Mf_pressure(int chan, int key, int val)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("pressurer"));
parameter.r = val / 127.0;
update(chan, key, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_controller(int chan, int control, int val)
{
Alg_parameter parameter;
char name[32];
#pragma warning(disable: 4996) // name is long enough
sprintf(name, "control%dr", control);
#pragma warning(default: 4996)
parameter.set_attr(symbol_table.insert_string(name));
parameter.r = val / 127.0;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_pitchbend(int chan, int c1, int c2)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("bendr"));
parameter.r = ((c2 << 7) + c1) / 8192.0 - 1.0;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_program(int chan, int program)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("programi"));
parameter.i = program;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::Mf_chanpressure(int chan, int val)
{
Alg_parameter parameter;
parameter.set_attr(symbol_table.insert_string("pressurer"));
parameter.r = val / 127.0;
update(chan, -1, &parameter);
meta_channel = -1;
}
void Alg_midifile_reader::binary_msg(int len, unsigned char *msg,
const char *attr_string)
{
Alg_parameter parameter;
char *hexstr = new char[len * 2 + 1];
for (int i = 0; i < len; i++) {
#pragma warning(disable: 4996) // hexstr is long enough
sprintf(hexstr + 2 * i, "%02x", (0xFF & msg[i]));
#pragma warning(default: 4996)
}
parameter.s = hexstr;
parameter.set_attr(symbol_table.insert_string(attr_string));
update(meta_channel, -1, &parameter);
}
void Alg_midifile_reader::Mf_sysex(int len, unsigned char *msg)
{
// sysex messages become updates with attribute sysexs and a hex string
binary_msg(len, msg, "sysexs");
}
void Alg_midifile_reader::Mf_arbitrary(int len, unsigned char *msg)
{
Mf_error("arbitrary data ignored");
}
void Alg_midifile_reader::Mf_metamisc(int type, int len, unsigned char *msg)
{
char text[128];
#pragma warning(disable: 4996) // text is long enough
sprintf(text, "metamsic data, type 0x%x, ignored", type);
#pragma warning(default: 4996)
Mf_error(text);
}
void Alg_midifile_reader::Mf_seqnum(int n)
{
Mf_error("seqnum data ignored");
}
static char *fpsstr[4] = {"24", "25", "29.97", "30"};
void Alg_midifile_reader::Mf_smpte(int hours, int mins, int secs,
int frames, int subframes)
{
// string will look like "24fps:01h:27m:07s:19.00f"
// 30fps (drop frame) is notated as "29.97fps"
char text[32];
int fps = (hours >> 6) & 3;
hours &= 0x1F;
#pragma warning(disable: 4996) // text is long enough
sprintf(text, "%sfps:%02dh:%02dm:%02ds:%02d.%02df",
fpsstr[fps], hours, mins, secs, frames, subframes);
#pragma warning(default: 4996)
Alg_parameter smpteoffset;
smpteoffset.s = heapify(text);
smpteoffset.set_attr(symbol_table.insert_string("smpteoffsets"));
update(meta_channel, -1, &smpteoffset);
// Mf_error("SMPTE data ignored");
}
void Alg_midifile_reader::Mf_timesig(int i1, int i2, int i3, int i4)
{
seq->set_time_sig(double(get_currtime()) / divisions, i1, 1 << i2);
}
void Alg_midifile_reader::Mf_tempo(int tempo)
{
double beat = get_currtime();
beat = beat / divisions; // convert to quarters
// 6000000 us/min / n us/beat => beat / min
double bpm = 60000000.0 / tempo;
seq->insert_tempo(bpm, beat);
}
void Alg_midifile_reader::Mf_keysig(int key, int mode)
{
Alg_parameter key_parm;
key_parm.set_attr(symbol_table.insert_string("keysigi"));
// use 0 for C major, 1 for G, -1 for F, etc., that is,
// the number of sharps, where flats are negative sharps
key_parm.i = key; //<<<---- fix this
// use -1 to mean "all channels"
update(meta_channel, -1, &key_parm);
Alg_parameter mode_parm;
mode_parm.set_attr(symbol_table.insert_string("modea"));
mode_parm.a = (mode == 0 ? symbol_table.insert_string("major") :
symbol_table.insert_string("minor"));
update(meta_channel, -1, &mode_parm);
}
void Alg_midifile_reader::Mf_sqspecific(int len, unsigned char *msg)
{
// sequencer specific messages become updates with attribute sqspecifics
// and a hex string for the value
binary_msg(len, msg, "sqspecifics");
}
char *heapify2(int len, unsigned char *s)
{
char *h = new char[len + 1];
memcpy(h, s, len);
h[len] = 0;
return h;
}
void Alg_midifile_reader::Mf_text(int type, int len, unsigned char *msg)
{
Alg_parameter text;
text.s = heapify2(len, msg);
const char *attr = "miscs";
if (type == 1) attr = "texts";
else if (type == 2) attr = "copyrights";
else if (type == 3)
attr = (track_number == 0 ? "seqnames" : "tracknames");
else if (type == 4) attr = "instruments";
else if (type == 5) attr = "lyrics";
else if (type == 6) attr = "markers";
else if (type == 7) attr = "cues";
text.set_attr(symbol_table.insert_string(attr));
update(meta_channel, -1, &text);
}
// parse file into a seq.
Alg_error alg_smf_read(istream &file, Alg_seq_ptr new_seq)
{
assert(new_seq);
Alg_midifile_reader ar(file, new_seq);
bool err = ar.parse();
ar.seq->set_real_dur(ar.seq->get_time_map()->
beat_to_time(ar.seq->get_beat_dur()));
return (err ? alg_error_syntax : alg_no_error);
}

View File

@@ -34,7 +34,7 @@ public:
// chan is actual_channel + channels_per_track * track_number
// default is 100, set this to 0 to merge all tracks to 16 channels
void write(ofstream &file /* , midiFileFormat = 1 */);
void write(ostream &file /* , midiFileFormat = 1 */);
private:
long previous_divs; // time in ticks of most recently written event
@@ -46,7 +46,7 @@ private:
void write_note(Alg_note_ptr note, bool on);
void write_update(Alg_update_ptr update);
void write_text(Alg_update_ptr update, char type);
void write_binary(int type_byte, char *msg);
void write_binary(int type_byte, const char *msg);
void write_midi_channel_prefix(Alg_update_ptr update);
void write_smpteoffset(Alg_update_ptr update, char *s);
void write_data(int data);
@@ -162,7 +162,7 @@ void Alg_smf_write::write_note(Alg_note_ptr note, bool on)
//printf("deltaDivisions: %d, beats elapsed: %g, on? %c\n", deltaDivisions, note->time, on);
char chan = (note->chan & 15);
char chan = char(note->chan & 15);
int pitch = int(note->pitch + 0.5);
if (pitch < 0) {
pitch = pitch % 12;
@@ -184,8 +184,8 @@ void Alg_smf_write::write_midi_channel_prefix(Alg_update_ptr update)
{
if (update->chan >= 0) { // write MIDI Channel Prefix
write_delta(update->time);
out_file->put(0xFF); // Meta Event
out_file->put(0x20); // Type code for MIDI Channel Prefix
out_file->put('\xFF'); // Meta Event
out_file->put('\x20'); // Type code for MIDI Channel Prefix
out_file->put(1); // length
out_file->put(to_midi_channel(update->chan));
// one thing odd about the Std MIDI File spec is that once
@@ -201,7 +201,7 @@ void Alg_smf_write::write_text(Alg_update_ptr update, char type)
{
write_midi_channel_prefix(update);
write_delta(update->time);
out_file->put(0xFF);
out_file->put('\xFF');
out_file->put(type);
out_file->put((char) strlen(update->parameter.s));
*out_file << update->parameter.s;
@@ -212,8 +212,8 @@ void Alg_smf_write::write_smpteoffset(Alg_update_ptr update, char *s)
{
write_midi_channel_prefix(update);
write_delta(update->time);
out_file->put(0xFF); // meta event
out_file->put(0x54); // smpte offset type code
out_file->put('\xFF'); // meta event
out_file->put('\x54'); // smpte offset type code
out_file->put(5); // length
for (int i = 0; i < 5; i++) *out_file << s[i];
}
@@ -255,13 +255,13 @@ static char hex_to_nibble(char c)
}
static char hex_to_char(char *s)
static char hex_to_char(const char *s)
{
return (hex_to_nibble(s[0]) << 4) + hex_to_nibble(s[1]);
}
void Alg_smf_write::write_binary(int type_byte, char *msg)
void Alg_smf_write::write_binary(int type_byte, const char *msg)
{
int len = strlen(msg) / 2;
out_file->put(type_byte);
@@ -275,7 +275,7 @@ void Alg_smf_write::write_binary(int type_byte, char *msg)
void Alg_smf_write::write_update(Alg_update_ptr update)
{
char *name = update->parameter.attr_name();
const char *name = update->parameter.attr_name();
/****Non-Meta Events****/
if (!strcmp(name, "pressurer")) {
@@ -312,7 +312,7 @@ void Alg_smf_write::write_update(Alg_update_ptr update)
write_data(val);
} else if (!strcmp(name, "sysexs") &&
update->parameter.attr_type() == 's') {
char *s = update->parameter.s;
const char *s = update->parameter.s;
if (s[0] && s[1] && toupper(s[0]) == 'F' && s[1] == '0') {
s += 2; // skip the initial "F0" byte in message: it is implied
}
@@ -320,9 +320,9 @@ void Alg_smf_write::write_update(Alg_update_ptr update)
write_binary(0xF0, s);
} else if (!strcmp(name, "sqspecifics") &&
update->parameter.attr_type() == 's') {
char *s = update->parameter.s;
const char *s = update->parameter.s;
write_delta(update->time);
out_file->put(0xFF);
out_file->put('\xFF');
write_binary(0x7F, s);
/****Text Events****/
@@ -349,11 +349,11 @@ void Alg_smf_write::write_update(Alg_update_ptr update)
// smpteoffset is specified as "24fps:00h:10m:00s:11.00f"
// the following simple parser does not reject all badly
// formatted strings, but it should parse good strings ok
char *s = update->parameter.s;
const char *s = update->parameter.s;
int len = strlen(s);
char smpteoffset[5];
if (len < 24) return; // not long enough, must be bad format
int fps = 0;
int fps;
if (s[0] == '2') {
if (s[1] == '4') fps = 0;
else if (s[1] == '5') fps = 1;
@@ -390,8 +390,8 @@ void Alg_smf_write::write_update(Alg_update_ptr update)
}
if (keysig != -99 && keysig_mode) { // write when both are defined
write_delta(keysig_when);
out_file->put(0xFF);
out_file->put(0x59);
out_file->put('\xFF');
out_file->put('\x59');
out_file->put(2);
// mask off high bits so that this value appears to be positive
// i.e. -1 -> 0xFF (otherwise, write_data will clip -1 to 0)
@@ -482,9 +482,9 @@ void Alg_smf_write::write_tempo(int divs, int tempo)
// printf("Inserting tempo %f after %f clocks.\n", tempo, delta);
write_varinum(divs - previous_divs);
previous_divs = divs;
out_file->put(0xFF);
out_file->put(0x51);
out_file->put(0x03);
out_file->put('\xFF');
out_file->put('\x51');
out_file->put('\x03');
write_24bit((int)tempo);
}
@@ -512,12 +512,11 @@ void Alg_smf_write::write_tempo_change(int i)
void Alg_smf_write::write_time_signature(int i)
{
Alg_time_sigs &ts = seq->time_sig;
write_delta(ts[i].beat);
// write the time signature
long divs = ROUND(ts[i].beat * division);
write_varinum(divs - previous_divs);
out_file->put(0xFF);
out_file->put(0x58); // time signature
out_file->put(4); // length of message
out_file->put('\xFF');
out_file->put('\x58'); // time signature
out_file->put('\x04'); // length of message
out_file->put(ROUND(ts[i].num));
int den = ROUND(ts[i].den);
int den_byte = 0;
@@ -532,7 +531,7 @@ void Alg_smf_write::write_time_signature(int i)
void Alg_smf_write::write(ofstream &file)
void Alg_smf_write::write(ostream &file)
{
int track_len_offset;
int track_end_offset;
@@ -564,9 +563,9 @@ void Alg_smf_write::write(ofstream &file)
// End of track event
write_varinum(0); // delta time
out_file->put(0xFF);
out_file->put(0x2F);
out_file->put(0x00);
out_file->put('\xFF');
out_file->put('\x2F');
out_file->put('\x00');
// Go back and write in the length of the track
track_end_offset = out_file->tellp();
@@ -632,7 +631,7 @@ void Alg_smf_write::write_varinum(int value)
}
void Alg_seq::smf_write(ofstream &file)
void Alg_seq::smf_write(ostream &file)
{
Alg_smf_write writer(this);
writer.write(file);
@@ -646,4 +645,3 @@ bool Alg_seq::smf_write(const char *filename)
outf.close();
return true;
}

View File

@@ -1,6 +1,6 @@
// allegrowr.cpp -- write sequence to an Allegro file (text)
#include "debug.h"
#include "assert.h"
#include "stdlib.h"
#include <iostream>
#include <fstream>
@@ -56,32 +56,34 @@ Alg_event_ptr Alg_seq::write_track_name(ostream &file, int n,
// find a name and write it, return a pointer to it so the track
// writer knows what update (if any) to skip
{
Alg_event_ptr e = NULL;
Alg_event_ptr e = NULL; // e is the result, default is NULL
file << "#track " << n;
const char *attr = symbol_table.insert_string(
n == 0 ? "seqnames" : "tracknames");
// search for name in events with timestamp of 0
for (int i = 0; i < events.length(); i++) {
e = events[i];
if (e->time > 0) break;
if (e->is_update()) {
Alg_update_ptr u = (Alg_update_ptr) e;
Alg_event_ptr ue = events[i];
if (ue->time > 0) break;
if (ue->is_update()) {
Alg_update_ptr u = (Alg_update_ptr) ue;
if (u->parameter.attr == attr) {
file << " " << u->parameter.s;
e = ue; // return the update event we found
break;
}
}
}
file << endl;
return e;
file << endl; // end of line containing #track [<name>]
return e; // return parameter event with name if one was found
}
void Alg_seq::write(ostream &file, bool in_secs)
void Alg_seq::write(ostream &file, bool in_secs, double offset)
{
int i, j;
if (in_secs) convert_to_seconds();
else convert_to_beats();
file << "#offset " << offset << endl;
Alg_event_ptr update_to_skip = write_track_name(file, 0, track_list[0]);
Alg_beats &beats = time_map->beats;
for (i = 0; i < beats.len - 1; i++) {
@@ -171,11 +173,11 @@ void Alg_seq::write(ostream &file, bool in_secs)
}
}
bool Alg_seq::write(const char *filename)
bool Alg_seq::write(const char *filename, double offset)
{
ofstream file(filename);
if (file.fail()) return false;
write(file, units_are_seconds);
file.close();
return true;
write(file, units_are_seconds, offset);
file.close();
return true;
}

View File

@@ -13,6 +13,7 @@
#include "stdio.h"
#include "mfmidi.h"
#include "string.h"
#include "assert.h"
#define MIDIFILE_ERROR -1
@@ -34,15 +35,16 @@ void Midifile_reader::midifile()
while (ntrks-- > 0 && !midifile_error) readtrack();
}
int Midifile_reader::readmt(const char *s, int skip)
int Midifile_reader::readmt(char *s, int skip)
/* read through the "MThd" or "MTrk" header string */
/* if skip == 1, we attempt to skip initial garbage. */
{
assert(strlen(s) == 4); // must be "MThd" or "MTrk"
int nread = 0;
char b[4];
char buff[32];
int c;
const char *errmsg = "expecting ";
char *errmsg = "expecting ";
retry:
while ( nread<4 ) {
@@ -66,8 +68,10 @@ int Midifile_reader::readmt(const char *s, int skip)
goto retry;
}
err:
#pragma warning(disable: 4996) // strcpy is safe since strings have known lengths
(void) strcpy(buff,errmsg);
(void) strcat(buff,s);
#pragma warning(default: 4996) // turn it back on
mferror(buff);
return(0);
}
@@ -189,7 +193,7 @@ void Midifile_reader::readtrack()
msginit();
while ( Mf_toberead > lookfor ) {
char c = egetc();
unsigned char c = egetc();
if (midifile_error) return;
msgadd(c);
}
@@ -253,15 +257,17 @@ void Midifile_reader::readtrack()
void Midifile_reader::badbyte(int c)
{
char buff[32];
#pragma warning(disable: 4996) // safe in this case
(void) sprintf(buff,"unexpected byte: 0x%02x",c);
#pragma warning(default: 4996)
mferror(buff);
}
void Midifile_reader::metaevent(int type)
{
int leng = msgleng();
char *m = msg();
// made this unsigned to avoid sign extend
unsigned char *m = msg();
switch ( type ) {
case 0x00:
@@ -408,7 +414,7 @@ int Midifile_reader::read16bit()
return to16bit(c1,c2);
}
void Midifile_reader::mferror(const char *s)
void Midifile_reader::mferror(char *s)
{
Mf_error(s);
midifile_error = 1;
@@ -444,7 +450,7 @@ void Midifile_reader::msginit()
Msgindex = 0;
}
char *Midifile_reader::msg()
unsigned char *Midifile_reader::msg()
{
return(Msgbuff);
}
@@ -464,21 +470,16 @@ void Midifile_reader::msgadd(int c)
void Midifile_reader::msgenlarge()
{
char *newmess;
char *oldmess = Msgbuff;
unsigned char *newmess;
unsigned char *oldmess = Msgbuff;
int oldleng = Msgsize;
Msgsize += MSGINCREMENT;
newmess = (char *) Mf_malloc((sizeof(char) * Msgsize) );
newmess = (unsigned char *) Mf_malloc((sizeof(unsigned char) * Msgsize) );
/* copy old message into larger new one */
if ( oldmess != 0 ) {
register char *p = newmess;
register char *q = oldmess;
register char *endq = &oldmess[oldleng];
for ( ; q!=endq ; p++,q++ )
*p = *q;
memcpy(newmess, oldmess, oldleng);
Mf_free(oldmess, oldleng);
}
Msgbuff = newmess;

View File

@@ -46,7 +46,7 @@ protected:
virtual void Mf_chanprefix(int) = 0;
virtual void Mf_portprefix(int) = 0;
virtual void Mf_eot() = 0;
virtual void Mf_error(const char *) = 0;
virtual void Mf_error(char *) = 0;
virtual void Mf_header(int,int,int) = 0;
virtual void Mf_on(int,int,int) = 0;
virtual void Mf_off(int,int,int) = 0;
@@ -55,16 +55,16 @@ protected:
virtual void Mf_pitchbend(int,int,int) = 0;
virtual void Mf_program(int,int) = 0;
virtual void Mf_chanpressure(int,int) = 0;
virtual void Mf_sysex(int,char*) = 0;
virtual void Mf_arbitrary(int,char*) = 0;
virtual void Mf_metamisc(int,int,char*) = 0;
virtual void Mf_sysex(int,unsigned char*) = 0;
virtual void Mf_arbitrary(int,unsigned char*) = 0;
virtual void Mf_metamisc(int,int,unsigned char*) = 0;
virtual void Mf_seqnum(int) = 0;
virtual void Mf_smpte(int,int,int,int,int) = 0;
virtual void Mf_timesig(int,int,int,int) = 0;
virtual void Mf_tempo(int) = 0;
virtual void Mf_keysig(int,int) = 0;
virtual void Mf_sqspecific(int,char*) = 0;
virtual void Mf_text(int,int,char*) = 0;
virtual void Mf_sqspecific(int,unsigned char*) = 0;
virtual void Mf_text(int,int,unsigned char*) = 0;
private:
long Mf_toberead;
@@ -73,7 +73,7 @@ private:
long read32bit();
int read16bit();
void msgenlarge();
char *msg();
unsigned char *msg();
int readheader();
void readtrack();
void sysex();
@@ -81,16 +81,16 @@ private:
int egetc();
int msgleng();
int readmt(const char *, int);
int readmt(char*,int);
long to32bit(int,int,int,int);
int to16bit(int,int);
void mferror(const char *);
void mferror(char *);
void badbyte(int);
void metaevent(int);
void msgadd(int);
void chanmessage(int,int,int);
char *Msgbuff;
unsigned char *Msgbuff;
long Msgsize;
long Msgindex;
};

View File

@@ -1,5 +1,5 @@
#include <cstring>
#include <string>
#include <cstring>
// #include <iostream> -- for debugging (cout)
#include "ctype.h"
using namespace std;
@@ -48,10 +48,10 @@ void String_parse::get_nonspace_quoted(string &field)
}
char *escape_chars[] = { (char *) "\\n", (char *)"\\t", (char *)"\\\\", (char *)"\\r", (char *) "\\\""};
static const char *const escape_chars[] = {"\\n", "\\t", "\\\\", "\\r", "\\\""};
void string_escape(string &result, char *str, const char *quote)
void string_escape(string &result, const char *str, const char *quote)
{
int length = (int) strlen(str);
if (quote[0]) {
@@ -59,8 +59,8 @@ void string_escape(string &result, char *str, const char *quote)
}
for (int i = 0; i < length; i++) {
if (!isalnum((unsigned char) str[i])) {
char *chars = (char *)"\n\t\\\r\"";
char *special = strchr(chars, str[i]);
const char *const chars = "\n\t\\\r\"";
const char *const special = strchr(chars, str[i]);
if (special) {
result.append(escape_chars[special - chars]);
} else {
@@ -78,7 +78,7 @@ void String_parse::get_remainder(std::string &field)
field.clear();
skip_space();
int len = str->length() - pos;
if ((*str)[len - 1] == '\n') { // if str ends in newline,
if ((len > 0) && ((*str)[len - 1] == '\n')) { // if str ends in newline,
len--; // reduce length to ignore newline
}
field.insert(0, *str, pos, len);

View File

@@ -15,4 +15,4 @@ public:
void get_remainder(std::string &field);
};
void string_escape(std::string &result, char *s, const char *quote);
void string_escape(std::string &result, const char *s, const char *quote);

View File

@@ -15,7 +15,7 @@ void trace(char *format, ...)
char msg[256];
va_list args;
va_start(args, format);
_vsnprintf(msg, 256, format, args);
_vsnprintf_s(msg, 256, _TRUNCATE, format, args);
va_end(args);
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN, NULL, NULL, NULL, msg);