/usr/include/portSMF/allegro.h is in libportsmf-dev 0.1~svn20101010-5ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 | // Portsmf (also known as Allegro):
// music representation system, with
// extensible in-memory sequence structure
// upward compatible with MIDI
// implementations in C++ and Serpent
// external, text-based representation
// compatible with Aura
//
// SERIALBUFFER CLASS
//
// The Serial_buffer class is defined to support serialization and
// unserialization. A Serial_buffer is just a block of memory with
// a length and a read/write pointer. When writing, it can expand.
//
// SERIALIZATION
//
// The Alg_track class has static members:
// ser_buf -- a Serial_buffer
// When objects are serialized, they are first written to
// ser_buf, which is expanded whenever necessary. Then, when
// the length is known, new memory is allocated and the data
// is copied to a correctly-sized buffer and returned to caller.
// The "external" (callable from outside the library)
// serialization functions are:
// Alg_track::serialize()
// Alg_seq::serialize()
// The "internal" serialization functions to be called from within
// the library are:
// Alg_track::serialize_track(bool text)
// Alg_seq::serialize_seq(bool text)
// Alg_track::serialize_parameter(
// Alg_parameter *parm, bool text)
// These internal serialize functions append data to ser_buf The text
// flag says to write an ascii representation as opposed to binary.
//
// UNSERIALIZATION:
//
// The Alg_track class has a static member:
// unserialize(char *buffer, long len)
// that will unserialize anything -- an Alg_track or an Alg_seq.
// No other function should be called from outside the library.
// Internal unserialize functions are:
// Alg_seq::unserialize_seq()
// Alg_track::unserialize_track()
// Alg_track::unserialize_parameter(Alg_parameter_ptr parm_ptr)
// 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_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
// are d1 and d2 within epsilon of each other?
bool within(double d1, double d2, double epsilon);
char *heapify(const char *s); // put a string on the heap
// Alg_attribute is an atom in the symbol table
// with the special addition that the last
// character is prefixed to the string; thus,
// the attribute 'tempor' (a real) is stored
// as 'rtempor'. To get the string name, just
// use attribute+1.
typedef const char *Alg_attribute;
#define alg_attr_name(a) ((a) + 1)
#define alg_attr_type(a) (*(a))
// Alg_atoms is a symbol table of Alg_attributes and other
// unique strings
class Alg_atoms {
public:
Alg_atoms() {
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)
Alg_attribute insert_string(const char *name);
private:
long maxlen;
long len;
Alg_attribute *atoms;
// insert an Attriubute not in table after moving attr to heap
Alg_attribute insert_new(const char *name, char attr_type);
void expand(); // make more space
};
extern Alg_atoms symbol_table;
// an attribute/value pair. Since Alg_attribute names imply type,
// we try to keep attributes and values packaged together as
// Alg_parameter class
typedef class Alg_parameter {
public:
// 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
const char *s; // string
long i; // integer
bool l; // logical
const char *a; // symbol (atom)
}; // anonymous union
Alg_parameter() { attr = "i"; }
~Alg_parameter();
void copy(Alg_parameter *); // copy from another parameter
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;
// a list of attribute/value pairs
typedef class Alg_parameters {
public:
class Alg_parameters *next;
Alg_parameter parm;
Alg_parameters(Alg_parameters *list) {
next = list;
}
//~Alg_parameters() { }
// each of these routines takes address of pointer to the list
// insertion is performed without checking whether or not a
// parameter already exists with this attribute. See find() and
// remove_key() to assist in checking for and removing existing
// parameters.
// Note also that these insert_* methods convert name to an
// 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, const char *name, double r);
// insert string will copy string to heap
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_parameters_ptr;
// these are type codes associated with certain attributes
// see Alg_track::find() where these are bit positions in event_type_mask
#define ALG_NOTE 0 // This is a note, not an update
#define ALG_GATE 1 // "gate"
#define ALG_BEND 2 // "bend"
#define ALG_CONTROL 3 // "control"
#define ALG_PROGRAM 4 // "program"
#define ALG_PRESSURE 5 // "pressure"
#define ALG_KEYSIG 6 // "keysig"
#define ALG_TIMESIG_NUM 7 // "timesig_num"
#define ALG_TIMESIG_DEN 8 // "timesig_den"
#define ALG_OTHER 9 // any other value
// abstract superclass of Alg_note and Alg_update:
typedef class Alg_event {
protected:
bool selected;
char type; // 'e' event, 'n' note, 'u' update
long key; // note identifier
static const char* description; // static buffer for debugging (in Alg_event)
public:
double time;
long chan;
virtual void show() = 0;
// Note: there is no Alg_event() because Alg_event is an abstract class.
bool is_note() { return (type == 'n'); } // tell whether an Alg_event is a note
bool is_update() { return (type == 'u'); } // tell whether an Alg_event is a parameter update
char get_type() { return type; } // return 'n' for note, 'u' for update
int get_type_code(); // 1 = volume change, 2 = pitch bend,
// 3 = control change, 4 = program change,
// 5 = pressure change, 6 = key signature,
// 7 = time sig numerator, 8 = time sig denominator
bool get_selected() { return selected; }
void set_selected(bool b) { selected = b; }
// Note: notes are identified by a (channel, identifier) pair.
// For midi, the identifier is the key number (pitch). The identifier
// does not have to represent pitch; it's main purpose is to identify
// notes so that they can be named by subsequent update events.
long get_identifier() { return key; } // get MIDI key or note identifier of note or update
void set_identifier(long i) { key = i; } // set the identifier
// In all of these set_ methods, strings are owned by the caller and
// copied as necessary by the callee. For notes, an attribute/value
// pair is added to the parameters list. For updates, the single
// attribute/value parameter pair is overwritten. In all cases, the
// 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(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:
//
float get_pitch();// get pitch in steps -- use this even for MIDI
float get_loud(); // get loudness (MIDI velocity)
// times are in seconds or beats, depending upon the units_are_seconds
// flag in the containing sequence
double get_start_time(); // get start time in seconds or beats
double get_end_time(); // get end time in seconds or beats
double get_duration(); // get duration in seconds or beats
void set_pitch(float);
void set_loud(float);
void set_duration(double);
// Notes have lists of attribute values. Attributes are converted
// to/from strings in this API to avoid explicit use of Alg_attribute
// types. Attribute names end with a type designation: 's', 'r', 'l',
// 'i', or 'a'.
//
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
// 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.
// Attributes are converted to/from strings to avoid explicit use
// of Alg_attribute types.
//
const char *get_attribute(); // get the update's attribute (string)
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
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
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.
// Auxiliary function to aid in editing tracks
// Returns true if the event overlaps the given region
bool overlap(double t, double len, bool all);
const char *GetDescription(); // computes a text description of this event
// the result is in a static buffer, not thread-safe, just for debugging.
Alg_event() { selected = false; }
virtual ~Alg_event() {}
} *Alg_event_ptr;
typedef class Alg_note : public Alg_event {
public:
virtual ~Alg_note();
Alg_note(Alg_note *); // copy constructor
float pitch; // pitch in semitones (69 = A440)
float loud; // dynamic corresponding to MIDI velocity
double dur; // duration in seconds (normally to release point)
Alg_parameters_ptr parameters; // attribute/value pair list
Alg_note() { type = 'n'; parameters = NULL; }
void show();
} *Alg_note_ptr;
typedef class Alg_update : public Alg_event {
public:
virtual ~Alg_update() {};
Alg_update(Alg_update *); // copy constructor
Alg_parameter parameter; // an update contains one attr/value pair
Alg_update() { type = 'u'; }
void show();
} *Alg_update_ptr;
// a sequence of Alg_event objects
typedef class Alg_events {
private:
long maxlen;
void expand();
protected:
long len;
Alg_event_ptr *events; // events is array of pointers
public:
// sometimes, it is nice to have the time of the last note-off.
// In the current implementation,
// this field is set by append to indicate the time of the
// last note-off in the current unit, so it should be correct after
// 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);
return events[i];
}
Alg_events() {
maxlen = len = 0;
events = NULL;
last_note_off = 0;
in_use = false;
}
// destructor deletes the events array, but not the
// events themselves
virtual ~Alg_events();
void set_events(Alg_event_ptr *e, long l, long m) {
if (events) delete [] events;
events = e; len = l; maxlen = m; }
// for use by Alg_track and Alg_seq
void insert(Alg_event_ptr event);
void append(Alg_event_ptr event);
Alg_event_ptr uninsert(long index);
} *Alg_events_ptr;
class Alg_track;
typedef class Alg_event_list : public Alg_events {
protected:
char type; // 'e' Alg_event_list, 't' Alg_track, 's' Alg_seq
static const char *last_error_message;
Alg_track *events_owner; // if this is an Alg_event_list,
// the events are owned by an Alg_track or an Alg_seq
static int sequences; // to keep track of sequence numbers
int sequence_number; // this sequence number is incremented
// whenever an edit is performed on an Alg_track or Alg_seq.
// When an Alg_event_list is created to contain pointers to
// a subset of an Alg_track or Alg_seq (the events_owner),
// the Alg_event_list gets a copy of the events_owner's
// sequence_number. If the events_owner is edited, the pointers
// in this Alg_event_list will become invalid. This is detected
// (for debugging) as differing sequence_numbers.
// every event list, track, and seq has a duration.
// Usually the duration is set when the list is constructed, e.g.
// when you extract from 10 to 15 seconds, the duration is 5 secs.
// The duration does not tell you when is the last note-off.
// duration is recorded in both beats and seconds:
double beat_dur;
double real_dur;
public:
// the client should not create one of these, but these are
// returned from various track and seq operations. An
// Alg_event_list "knows" the Alg_track or Alg_seq that "owns"
// the events. All events in an Alg_event_list must belong
// to the same Alg_track or Alg_seq structure.
// When applied to an Alg_seq, events are enumerated track
// by track with increasing indices. This operation is not
// particularly fast on an Alg_seq.
virtual Alg_event_ptr &operator[](int i);
Alg_event_list() { sequence_number = 0;
beat_dur = 0.0; real_dur = 0.0; events_owner = NULL; type = 'e'; }
Alg_event_list(Alg_track *owner);
char get_type() { return type; }
Alg_track *get_owner() { return events_owner; }
// The destructor does not free events because they are owned
// by a track or seq structure.
virtual ~Alg_event_list();
// Returns the duration of the sequence in beats or seconds
double get_beat_dur() { return beat_dur; }
void set_beat_dur(double d) { beat_dur = d; }
double get_real_dur() { return real_dur; }
void set_real_dur(double d) { real_dur = d; }
// Events are stored in time order, so when you change the time of
// an event, you must adjust the position. When you call set_start_time
// on an Alg_event_list, the Alg_event_list is not modified, but the
// Alg_track that "owns" the event is modified. If the owner is an
// Alg_seq, this may require searching the seq for the track containing
// the event. This will mean a logN search of every track in the seq
// (but if this turns out to be a problem, we can store each event's
// track owner in the Alg_event_list.)
virtual void set_start_time(Alg_event *event, double);
// get text description of run-time errors detected, clear error
const char *get_last_error_message() { return last_error_message; }
// Implementation hint: keep a sequence number on each Alg_track that is
// incremented anytime there is a structural change. (This behavior is
// inherited by Alg_seq as well.) Copy the sequence number to any
// Alg_event_list object when it is created. Whenever you access an
// Alg_event_list, using operator[], assert that the Alg_event_list sequence
// number matches the Alg_seq sequence number. This will guarantee that you
// do not try to retain pointers to events beyond the point where the events
// may no longer exist.
} *Alg_event_list_ptr, &Alg_event_list_ref;
// Alg_beat is used to contruct a tempo map
typedef class Alg_beat {
public:
Alg_beat(double t, double b) {
time = t; beat = b; }
Alg_beat() {};
double time;
double beat;
} *Alg_beat_ptr;
// Alg_beats is a list of Alg_beat objects used in Alg_seq
typedef class Alg_beats {
private:
long maxlen;
void expand();
public:
long len;
Alg_beat_ptr beats;
Alg_beat &operator[](int i) {
assert(i >= 0 && i < len);
return beats[i];
}
Alg_beats() {
maxlen = len = 0;
beats = NULL;
expand();
beats[0].time = 0;
beats[0].beat = 0;
len = 1;
}
~Alg_beats() {
if (beats) delete[] beats;
}
void insert(long i, Alg_beat_ptr beat);
} *Alg_beats_ptr;
typedef class Alg_time_map {
private:
int refcount;
public:
Alg_beats beats; // array of Alg_beat
double last_tempo;
bool last_tempo_flag;
Alg_time_map() {
last_tempo = ALG_DEFAULT_BPM / 60.0; // note: this value ignored until
// last_tempo_flag is set; nevertheless, the default
// tempo is 100.
last_tempo_flag = true;
refcount = 0;
}
Alg_time_map(Alg_time_map *map); // copy constructor
long length() { return beats.len; }
void show();
long locate_time(double time);
long locate_beat(double beat);
double beat_to_time(double beat);
double time_to_beat(double time);
// Time map manipulations: it is prefered to call the corresponding
// methods in Alg_seq. If you manipulate an Alg_time_map directly,
// you should take care to convert all tracks that use the time map
// to beats or seconds as appropriate: Normally if you insert a beat
// you want tracks to be in time units and if you insert a tempo change
// 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);
// insert a span of time. If start is at a tempo change, then
// the span of time runs at the changed tempo
void insert_time(double start, double len);
// insert a span of beats. If start is at a tempo change, the
// tempo change takes effect before the inserted beats
void insert_beats(double start, double len);
void dereference() {
if (--refcount <= 0) delete this;
}
void reference() {
refcount++;
}
} *Alg_time_map_ptr;
// 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:
Serial_buffer() {
buffer = NULL;
ptr = NULL;
len = 0;
}
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);
long *loc = (long *) (buffer + offset);
*loc = value;
}
void check_buffer(long needed);
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);
// 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; }
#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();
char *newbuf = new char[*len];
memcpy(newbuf, buffer, *len);
return newbuf;
}
} *Serial_write_buffer_ptr;
typedef class Alg_seq *Alg_seq_ptr;
typedef class Alg_track : public Alg_event_list {
protected:
Alg_time_map *time_map;
bool units_are_seconds;
char *get_string(char **p, long *b);
long get_int32(char **p, long *b);
double get_double(char **p, long *b);
float get_float(char **p, long *b);
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
void unserialize_parameter(Alg_parameter_ptr parm_ptr);
public:
void serialize_track();
void unserialize_track();
virtual Alg_event_ptr &operator[](int i) {
assert(i >= 0 && i < len);
return events[i];
}
Alg_track() { units_are_seconds = false; time_map = NULL;
set_time_map(NULL); type = 't'; }
// initialize empty track with a time map
Alg_track(Alg_time_map *map, bool seconds);
Alg_event_ptr copy_event(Alg_event_ptr event); // make a complete copy
Alg_track(Alg_track &track); // copy constructor, does not copy time_map
// 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() { // 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.
// *buffer gets a newly allocated buffer pointer. The caller must free it.
// *len gets the length of the serialized track
virtual void serialize(void **buffer, long *bytes);
// Try to read from a memory buffer. Automatically guess
// whether it's MIDI or text.
static Alg_track *unserialize(void *buffer, long len);
// If the track is really an Alg_seq and you need to access an
// Alg_seq method, coerce to an Alg_seq with this function:
Alg_seq_ptr to_alg_seq() {
return (get_type() == 's' ? (Alg_seq_ptr) this : NULL); }
// Are we using beats or seconds?
bool get_units_are_seconds() { return units_are_seconds; }
// Change units
virtual void convert_to_beats();
virtual void convert_to_seconds();
void set_dur(double dur);
double get_dur() { return (units_are_seconds ? real_dur : beat_dur); }
// Every Alg_track may have an associated time_map. If no map is
// specified, or if you set_time_map(NULL), then the behavior
// should be as if there is a constant tempo of 100 beats/minute
// (this constant is determined by ALG_DEFAULT_BPM).
// Recommendation: create a static global tempo map object. When
// any operation that needs a tempo map gets NULL, use the global
// tempo map. (Exception: any operation that would modify the
// tempo map should raise an error -- you don't want to change the
// default tempo map.)
virtual void set_time_map(Alg_time_map *map);
Alg_time_map *get_time_map() { return time_map; }
// Methods to create events. The returned event is owned by the caller.
// Use delete to get rid of it unless you call add() -- see below.
//
Alg_note *create_note(double time, int channel, int identifier,
float pitch, float loudness, double duration);
// Note: after create_update(), caller should use set_*_value() to
// initialize the attribute/value pair:
Alg_update *create_update(double time, int channel, int identifier);
// Adds a new event - it is automatically inserted into the
// correct order in the sequence based on its timestamp.
// The ownership passes from the caller to this Alg_seq. The
// event is not copied.
virtual void add(Alg_event *event) { insert(event); }
//
// Editing regions
//
// Deletes the notes that start within the given region
// and returns them in a new sequence. The start times
// of the notes in the returned sequence are shifted
// by -t. The notes after the region get shifted over
// to fill the gap. In an Alg_seq, the tempo track is edited
// in a similar way
// and the cut tempo information is retained in the new seq.
// ONLY NOTES THAT START WITHIN THE REGION ARE CUT unless
// "all" is true in which case all notes that intersect
// the region are copied. CUT NOTES
// MAY EXTEND BEYOND THE DURATION OF THE RESULTING SEQ.
// The return type is the same as this (may be Alg_seq).
// All times including len are interpreted according to
// units_are_seconds in the track.
virtual Alg_track *cut(double t, double len, bool all);
// Like cut() but doesn't remove the notes from the original
// sequence. The Alg_events are copied, not shared. ONLY EVENTS
// THAT START WITHIN THE REGION ARE COPIED unless "all" is true
// in which case all notes that intersect the region are
// copied. COPIED NOTES MAY
// EXTEND BEYOND THE DURATION OF THE RESULTING SEQ.
// The return type is the same as this (may be Alg_seq).
virtual Alg_track *copy(double t, double len, bool all);
// Inserts a sequence in the middle, shifting some notes
// over by the duration of the seq, which is first converted
// to the same units (seconds or beats) as this. (This makes
// a differece because the pasted data may change the tempo,
// and notes that overlap the borders will then experience
// a tempo change.)
// THE SEQ PARAMETER IS NOT MODIFIED, AND Alg_event's ARE
// COPIED, NOT SHARED.
// The type of seq must be Alg_seq if seq is an Alg_seq, or
// Alg_track if seq is an Alg_track or an Alg_event_list.
virtual void paste(double t, Alg_event_list *seq); // Shifts notes
// Merges two sequences with a certain offset. The offset is
// interpreted as either beats or seconds according to the
// current units of this, and seq is converted to the same
// units as this. Except for a possible conversion to beats
// or seconds, the tempo track of seq (if any) is ignored.
// (There is no way to merge tempo tracks.)
// THE SEQ PARAMETER IS NOT MODIFIED, AND Alg_event's ARE
// COPIED, NOT SHARED.
// The type of seq must be Alg_seq if seq is an Alg_seq, or
// Alg_track if seq is an Alg_track or an Alg_event_list.
virtual void merge(double t, Alg_event_list_ptr seq);
// Deletes and shifts notes to fill the gap. The tempo track
// is also modified accordingly. ONLY EVENTS THAT START WITHIN
// THE REGION ARE DELETED unless "all" is true, in which case
// all notes that intersect the region are cleared.
// NOTES THAT EXTEND FROM BEFORE THE
// REGION INTO THE REGION RETAIN THEIR DURATION IN EITHER
// BEATS OR SECONDS ACCORDING TO THE CURRENT UNITS OF this.
virtual void clear(double t, double len, bool all);
// Deletes notes but doesn't shift. If the "all" argument
// is true, deletes all notes that intersect the range at all,
// not just those that start within it. The tempo track is
// not affected.
virtual void silence(double t, double len, bool all);
// Simply shifts notes past time t over by len, which is given
// in either beats or seconds according to the units of this.
// The resulting interveal (t, t+len) may in fact contain notes
// that begin before t. The durations of notes are not changed.
// If this is an Alg_seq, the tempo track is expanded at t also.
virtual void insert_silence(double t, double len);
//
// Accessing for screen display
//
// A useful generic function to retrieve only certain
// types of events. The masks should be bit-masks defined
// somewhere else. Part of the mask allows us to search for
// selected events. If this is an Alg_seq, search all tracks
// (otherwise, call track[i].find())
// If channel_mask == 0, accept ALL channels
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
//
// See Alg_iterator
} *Alg_track_ptr, &Alg_track_ref;
// Alg_time_sig represents a single time signature;
// although not recommended, time_signatures may have arbitrary
// floating point values, e.g. 4.5 beats per measure
typedef class Alg_time_sig {
public:
double beat; // when does this take effect?
double num; // what is the "numerator" (top number?)
double den; // what is the "denominator" (bottom number?)
Alg_time_sig(double b, double n, double d) {
beat = b; num = n; den = d;
}
Alg_time_sig() {
beat = 0; num = 0; den = 0;
}
void beat_to_measure(double beat, double *measure, double *m_beat,
double *num, double *den);
} *Alg_time_sig_ptr;
// Alg_time_sigs is a dynamic array of time signatures
//
// The default (empty) time_sigs has 4/4 time at beat 0.
// Each time_sig object in time_sigs represents the beginning
// of a measure. If there is a beat missing, e.g. in the first
// measure, you can represent this by inserting another
// time_sig at the next measure beginning. Each time_sig implies
// an infinite sequence of full measures until the next time_sig.
// If you insert a time_sig and one already exist near the same
// beat, the old one is replaced, thus re-barring every measure
// until the next time_sig.
class Alg_time_sigs {
private:
long maxlen;
void expand(); // make more space
long len;
Alg_time_sig_ptr time_sigs;
public:
Alg_time_sigs() {
maxlen = len = 0;
time_sigs = NULL;
}
Alg_time_sig &operator[](int i) { // fetch a time signature
assert(i >= 0 && i < len);
return time_sigs[i];
}
~Alg_time_sigs() {
if (time_sigs) delete[] time_sigs;
}
void show();
long length() { return len; }
int find_beat(double beat);
// 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);
};
// a sequence of Alg_events objects
typedef class Alg_tracks {
private:
long maxlen;
void expand();
void expand_to(int new_max);
long len;
public:
Alg_track_ptr *tracks; // tracks is array of pointers
Alg_track &operator[](int i) {
assert(i >= 0 && i < len);
return *tracks[i];
}
long length() { return len; }
Alg_tracks() {
maxlen = len = 0;
tracks = NULL;
}
~Alg_tracks();
// Append a track to tracks. This Alg_tracks becomes the owner of track.
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;
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:
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
Alg_event_ptr write_track_name(std::ostream &file, int n,
Alg_events &events);
public:
int channel_offset_per_track; // used to encode track_num into channel
Alg_tracks track_list; // array of Alg_events
Alg_time_sigs time_sig;
int beat_x;
void basic_initialization() {
error = alg_no_error;
units_are_seconds = true; type = 's';
channel_offset_per_track = 0;
add_track(0); // default is one empty track
}
Alg_seq() {
basic_initialization();
}
// copy constructor -- if track is an Alg_seq, make a copy; if
// track is just an Alg_track, the track becomes track 0
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);
// 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
void set_time_map(Alg_time_map *map);
// encode sequence structure into contiguous, moveable memory block
// address of newly allocated memory is assigned to *buffer, which must
// be freed by caller; the length of data is assigned to *len
void unserialize_seq();
// write an ascii representation to file
void write(std::ostream &file, bool in_secs, double offset = 0.0);
// returns true on success
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
int tracks();
// create a track
void add_track(int track_num) {
track_list.add_track(track_num, get_time_map(), units_are_seconds);
}
// Return a particular track. This Alg_seq owns the track, so the
// caller must not delete the result.
Alg_track_ptr track(int);
virtual Alg_event_ptr &operator[](int i);
virtual void convert_to_seconds();
virtual void convert_to_beats();
Alg_track_ptr cut_from_track(int track_num, double start, double dur,
bool all);
Alg_seq *cut(double t, double len, bool all);
void insert_silence_in_track(int track_num, double t, double len);
void insert_silence(double t, double len);
Alg_track_ptr copy_track(int track_num, double t, double len, bool all);
Alg_seq *copy(double start, double len, bool all);
void paste(double start, Alg_seq *seq);
virtual void clear(double t, double len, bool all);
virtual void merge(double t, Alg_event_list_ptr seq);
virtual void silence(double t, double len, bool all);
void clear_track(int track_num, double start, double len, bool all);
void silence_track(int track_num, double start, double len, bool all);
Alg_event_list_ptr find_in_track(int track_num, double t, double len,
bool all, long channel_mask,
long event_type_mask);
// 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
// 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 set_in_use(bool flag); // set in_use flag on all tracks
} *Alg_seq_ptr, &Alg_seq_ref;
// see Alg_seq::Alg_seq() constructors that read from files
// the following are for internal library implementation and are
// moved to *_internal.h header files.
//Alg_seq_ptr alg_read(std::istream &file, Alg_seq_ptr new_seq);
//Alg_seq_ptr alg_smf_read(std::istream &file, Alg_seq_ptr new_seq);
#endif
|