Update portsmf to latest r234 commit
This commit is contained in:
@@ -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
@@ -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 ¬e_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
@@ -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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
}
|
||||
|
||||
|
||||
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 = ¬e_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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
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, ¶meter);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user