1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-15 15:11:12 +02:00

Changes to allegro fix a bug where property lists are not properly saved/restored for Undo/Redo. Other changes make this code safer and more consistent between 32-bit and 64-bit architectures.

This commit is contained in:
Roger Dannenberg
2021-03-27 13:21:01 -04:00
parent 95a7fc6362
commit cd79f1099b
3 changed files with 217 additions and 116 deletions

View File

@@ -122,7 +122,7 @@ public:
union {
double r;// real
const char *s; // string
long i; // integer
int64_t i; // integer -- 64 bit for 32/64-bit compatibility
bool l; // logical
const char *a; // symbol (atom)
}; // anonymous union
@@ -162,7 +162,8 @@ public:
// 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_integer(Alg_parameters **list, const char *name,
int64_t 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);
@@ -190,11 +191,11 @@ 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)
int32_t key; // note identifier -- fixed at 32 bits
static const char* description; // static buffer for debugging
public:
double time;
long chan;
int32_t chan; // generalization of MIDI channels -- fixed at 32 bits
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
@@ -210,8 +211,10 @@ public:
// 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
// get MIDI key or note identifier of note or update:
int32_t get_identifier() { return key; }
void set_identifier(int32_t 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
@@ -222,7 +225,7 @@ public:
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_integer_value(const char *attr, int64_t value);
void set_atom_value(const char *attr, const char *atom);
// Some note methods. These fail (via assert()) if this is not a note:
@@ -246,7 +249,7 @@ public:
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),
// 'r' = real (double), 'l' = logical (bool), 'i' = integer (int64_t),
// '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);
@@ -255,7 +258,7 @@ public:
// 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);
int64_t get_integer_value(const char *attr, int64_t 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
@@ -267,14 +270,14 @@ public:
//
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),
// 'r' = real (double), 'l' = logical (bool), 'i' = integer (int64_t),
// '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
int64_t 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.
@@ -521,6 +524,25 @@ public:
} *Alg_time_map_ptr;
// Aligner is a simple class to allow 64-bit data to be stored and
// retrieved from Serial_buffer, where data is 32-bit aligned,
// in an architecture-independent fashion. On some architectures,
// read/writes of int64_t or doubles must be aligned to 8 bytes.
class Aligner {
public:
union {
int64_t i64;
double d64;
struct {
int32_t int32a;
int32_t int32b;
};
};
Aligner(double d) { d64 = d; }
Aligner(int64_t i) { i64 = i; }
Aligner(int32_t a, int32_t b) { int32a = a; int32b = b; }
};
// Serial_buffer is an abstract class with common elements of
// Serial_read_buffer and Serial_write_buffer
class Serial_buffer {
@@ -549,10 +571,12 @@ public:
// does nothing.
virtual ~Serial_read_buffer() { }
#if defined(_WIN32)
// TODO: revisit warning disables now that ptr is more properly cast
// to/from size_t (not long):
#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++; }
void get_pad() { while (((size_t) ptr) & 3) ptr++; }
#if defined(_WIN32)
#pragma warning(default: 4311 546)
#endif
@@ -566,11 +590,16 @@ public:
}
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; }
double get_double() {
int32_t a = get_int32();
int32_t b = get_int32();
Aligner aligner(a, b);
return aligner.d64; }
int32_t get_int32() { int32_t i = *((int32_t *) ptr); ptr += 4; return i; }
int64_t get_int64();
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;
ptr += strlen(s);
assert(ptr < fence);
while (*ptr++) assert(ptr < fence);
get_pad();
@@ -592,9 +621,9 @@ typedef class Serial_write_buffer: public Serial_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);
void store_int32(long offset, int32_t value) {
assert(offset <= get_posn() - sizeof(value));
int32_t *loc = (int32_t *) (buffer + offset);
*loc = value;
}
void check_buffer(long needed);
@@ -604,25 +633,32 @@ typedef class Serial_write_buffer: public Serial_buffer {
// two brackets surpress a g++ warning, because this is an
// assignment operator inside a test.
while ((*ptr++ = *s++)) assert(ptr < fence);
// TODO: revisit warning disables because now we are more
// properly casting pointer to size_t (not long) and back -RBD
// 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);
assert((char *)(((size_t) (ptr + 3)) & ~3) <= 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_int32(int32_t v) { *((int32_t *) ptr) = v; ptr += 4; }
void set_double(double v) {
Aligner aligner(v);
set_int32(aligner.int32a);
set_int32(aligner.int32b); }
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
// TODO: reassess warning disables now that pointer is more properly
// cast to/from size_t (not long):
#pragma warning(disable: 546) // cast to int is OK, we only want low few bits
#pragma warning(disable: 4311) // type cast pointer to long warning
#endif
void pad() { while (((long) ptr) & 7) set_char(0); }
void pad() { while (((size_t) ptr) & 3) set_char(0); }
#if defined(_WIN32)
#pragma warning(default: 4311 546)
#endif
@@ -640,10 +676,10 @@ 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);
// char *get_string(char **p, long *b); -- these seem to be orphaned
// int32_t get_int32(char **p, long *b); -- declarations. Maybe they
// double get_double(char **p, long *b); -- were intended for
// float get_float(char **p, long *b); -- serialization. Delete them?
static Serial_read_buffer ser_read_buf;
static Serial_write_buffer ser_write_buf;
void serialize_parameter(Alg_parameter *parm);
@@ -804,9 +840,11 @@ public:
// 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
// If channel_mask == 0, accept ALL channels, otherwise
// accept only channels < 32 where corresponding bit is set in
// channel_mask.
virtual Alg_event_list *find(double t, double len, bool all,
long channel_mask, long event_type_mask);
int32_t channel_mask, int32_t event_type_mask);
virtual void set_in_use(bool flag) { in_use = flag; }
//
@@ -1077,8 +1115,8 @@ public:
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);
bool all, int32_t channel_mask,
int32_t event_type_mask);
// find index of first score event after time
long seek_time(double time, int track_num);