mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 08:09:32 +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:
parent
95a7fc6362
commit
cd79f1099b
@ -15,6 +15,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -40,7 +41,7 @@
|
|||||||
#define NYX_FULL_COPY 1
|
#define NYX_FULL_COPY 1
|
||||||
|
|
||||||
/* show memory stats */
|
/* show memory stats */
|
||||||
// #define NYX_MEMORY_STATS 1
|
#define NYX_MEMORY_STATS 1
|
||||||
|
|
||||||
/* show details of obarray copy */
|
/* show details of obarray copy */
|
||||||
// #define NYX_DEBUG_COPY 1
|
// #define NYX_DEBUG_COPY 1
|
||||||
@ -485,7 +486,7 @@ void nyx_init()
|
|||||||
xlprot1(nyx_result);
|
xlprot1(nyx_result);
|
||||||
|
|
||||||
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
||||||
printf("\nnyx_init\n");
|
stdputstr("\nnyx_init\n");
|
||||||
xmem();
|
xmem();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -530,7 +531,7 @@ void nyx_cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
||||||
printf("\nnyx_cleanup\n");
|
stdputstr("\nnyx_cleanup\n");
|
||||||
xmem();
|
xmem();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -829,7 +830,7 @@ nyx_rval nyx_eval_expression(const char *expr_string)
|
|||||||
LVAL expr = NULL;
|
LVAL expr = NULL;
|
||||||
|
|
||||||
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
||||||
printf("\nnyx_eval_expression before\n");
|
stdputstr("\nnyx_eval_expression before\n");
|
||||||
xmem();
|
xmem();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -913,10 +914,11 @@ nyx_rval nyx_eval_expression(const char *expr_string)
|
|||||||
gc();
|
gc();
|
||||||
|
|
||||||
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
||||||
printf("\nnyx_eval_expression after\n");
|
stdputstr("\nnyx_eval_expression after\n");
|
||||||
xmem();
|
xmem();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
printf("nyx_eval_expression returns %d\n", nyx_get_type(nyx_result));
|
||||||
return nyx_get_type(nyx_result);
|
return nyx_get_type(nyx_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,12 +939,20 @@ int nyx_get_audio_num_channels()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see sndwritepa.c for similar computation. This is a bit simpler
|
||||||
|
// because we are not writing interleaved samples.
|
||||||
|
typedef struct {
|
||||||
|
int cnt; // how many samples are in the current sample block
|
||||||
|
sample_block_values_type samps; // the next sample
|
||||||
|
bool terminated; // has the sound reached termination?
|
||||||
|
} sound_state_node, *sound_state_type;
|
||||||
|
|
||||||
|
|
||||||
int nyx_get_audio(nyx_audio_callback callback, void *userdata)
|
int nyx_get_audio(nyx_audio_callback callback, void *userdata)
|
||||||
{
|
{
|
||||||
float *buffer = NULL;
|
sound_state_type states; // tracks progress reading multiple channels
|
||||||
sound_type *snds = NULL;
|
float *buffer = NULL; // samples to push to callback
|
||||||
int64_t *totals = NULL;
|
int64_t total = 0; // total frames computed (samples per channel)
|
||||||
int64_t *lens = NULL;
|
|
||||||
sound_type snd;
|
sound_type snd;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int num_channels;
|
int num_channels;
|
||||||
@ -954,35 +964,31 @@ int nyx_get_audio(nyx_audio_callback callback, void *userdata)
|
|||||||
// cached in registers to be lost.
|
// cached in registers to be lost.
|
||||||
volatile int success = FALSE;
|
volatile int success = FALSE;
|
||||||
|
|
||||||
|
printf("nyx_get_audio type %d\n", nyx_get_type(nyx_result));
|
||||||
if (nyx_get_type(nyx_result) != nyx_audio) {
|
if (nyx_get_type(nyx_result) != nyx_audio) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
||||||
printf("\nnyx_get_audio before\n");
|
stdputstr("\nnyx_get_audio before\n");
|
||||||
xmem();
|
xmem();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
num_channels = nyx_get_audio_num_channels();
|
num_channels = nyx_get_audio_num_channels();
|
||||||
|
|
||||||
buffer = (sample_type *) malloc(max_sample_block_len * sizeof(sample_type));
|
buffer = (sample_type *) malloc(max_sample_block_len * sizeof(sample_type *));
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
snds = (sound_type *) malloc(num_channels * sizeof(sound_type));
|
states = (sound_state_type) malloc(num_channels * sizeof(sound_state_node));
|
||||||
if (snds == NULL) {
|
if (states == NULL) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
for (ch = 0; ch < num_channels; ch++) {
|
||||||
totals = (int64_t *) malloc(num_channels * sizeof(int64_t));
|
states[ch].cnt = 0; // force initial fetch
|
||||||
if (totals == NULL) {
|
states[ch].samps = NULL; // unnecessary initialization
|
||||||
goto finish;
|
states[ch].terminated = false;
|
||||||
}
|
|
||||||
|
|
||||||
lens = (int64_t *) malloc(num_channels * sizeof(int64_t));
|
|
||||||
if (lens == NULL) {
|
|
||||||
goto finish;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup a new context
|
// Setup a new context
|
||||||
@ -996,6 +1002,10 @@ int nyx_get_audio(nyx_audio_callback callback, void *userdata)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if LEN is set, we will return LEN samples per channel. If LEN is
|
||||||
|
// unbound, we will compute samples until every channel has terminated
|
||||||
|
// that the samples per channel will match the last termination time,
|
||||||
|
// i.e. it could result in a partial block at the end.
|
||||||
if (nyx_input_length == 0) {
|
if (nyx_input_length == 0) {
|
||||||
LVAL val = getvalue(xlenter("LEN"));
|
LVAL val = getvalue(xlenter("LEN"));
|
||||||
if (val != s_unbound) {
|
if (val != s_unbound) {
|
||||||
@ -1008,54 +1018,96 @@ int nyx_get_audio(nyx_audio_callback callback, void *userdata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// at this point, input sounds which were referenced by symbol S
|
||||||
|
// (or nyx_get_audio_name()) could be referenced by nyx_result, but
|
||||||
|
// S is now bound to NIL. nyx_result is a protected (garbage
|
||||||
|
// collected) LVAL bound to a sound or array of sounds, so we must
|
||||||
|
// either unbind nyx_result or read it destructively. We need the
|
||||||
|
// GC to know about sounds as we read them, so we might as well
|
||||||
|
// read nyx_result destructively. However, reading destructively
|
||||||
|
// will fail if nyx_result is (VECTOR S S) or has two references to
|
||||||
|
// the same sound. Therefore, we will replace each channel of
|
||||||
|
// nyx_result (except the first) with a copy. This may make
|
||||||
|
// needless copies, but if so, the GC will free the originals.
|
||||||
|
// Note: sound copies are just "readers" of the same underlying
|
||||||
|
// list of samples (snd_list_nodes) and lazy sample computation
|
||||||
|
// structure, so here, a sound copy is just one extra object of
|
||||||
|
// type sound_node.
|
||||||
|
// To unify single and multi-channel sounds, we'll create an array
|
||||||
|
// of one element for single-channel sounds.
|
||||||
|
|
||||||
|
if (num_channels == 1) {
|
||||||
|
LVAL array = newvector(1);
|
||||||
|
setelement(array, 0, nyx_result);
|
||||||
|
nyx_result = array;
|
||||||
|
}
|
||||||
for (ch = 0; ch < num_channels; ch++) {
|
for (ch = 0; ch < num_channels; ch++) {
|
||||||
if (num_channels == 1) {
|
if (ch > 0) { // no need to copy first channel
|
||||||
snd = getsound(nyx_result);
|
setelement(nyx_result, ch,
|
||||||
|
cvsound(sound_copy(getsound(getelement(nyx_result, ch)))));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
snd = getsound(getelement(nyx_result, ch));
|
|
||||||
}
|
|
||||||
snds[ch] = sound_copy(snd);
|
|
||||||
totals[ch] = 0;
|
|
||||||
lens[ch] = nyx_input_length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the "pump" that pulls samples from Nyquist and pushes samples
|
||||||
|
// out by calling the callback function. Every block boundary is a potential
|
||||||
|
// sound termination point, so we pull, scale, and write sample up to the
|
||||||
|
// next block boundary in any channel.
|
||||||
|
// First, we look at all channels to determine how many samples we have to
|
||||||
|
// compute in togo (how many "to go"). Then, we push togo samples from each
|
||||||
|
// channel to the callback, keeping all the channels in lock step.
|
||||||
|
|
||||||
while (result == 0) {
|
while (result == 0) {
|
||||||
for (ch =0 ; ch < num_channels; ch++) {
|
bool terminated = true;
|
||||||
|
// how many samples to compute before calling callback:
|
||||||
|
int64_t togo = max_sample_block_len;
|
||||||
|
if (nyx_input_length > 0 && total + togo > nyx_input_length) {
|
||||||
|
togo = nyx_input_length - total;
|
||||||
|
}
|
||||||
|
for (ch = 0; ch < num_channels; ch++) {
|
||||||
|
sound_state_type state = &states[ch];
|
||||||
|
sound_type snd = getsound(getelement(nyx_result, ch));
|
||||||
sample_block_type block;
|
sample_block_type block;
|
||||||
int cnt;
|
int cnt;
|
||||||
int i;
|
int i;
|
||||||
|
if (state->cnt == 0) {
|
||||||
snd = snds[ch];
|
state->samps = sound_get_next(snd, &state->cnt)->samples;
|
||||||
|
if (state->samps == zero_block->samples) {
|
||||||
cnt = 0;
|
state->terminated = true;
|
||||||
block = sound_get_next(snd, &cnt);
|
// Note: samps is a valid pointer to at least cnt zeros
|
||||||
if (block == zero_block || cnt == 0) {
|
// so we can process this channel as if it still has samples.
|
||||||
success = TRUE;
|
}
|
||||||
result = -1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
terminated &= state->terminated; // only terminated if ALL terminate
|
||||||
|
if (state->cnt < togo) togo = state->cnt;
|
||||||
|
// now togo is the minimum of: how much room is left in buffer and
|
||||||
|
// how many samples are available in samps
|
||||||
|
}
|
||||||
|
if (terminated || togo == 0) {
|
||||||
|
success = TRUE;
|
||||||
|
result = -1;
|
||||||
|
break; // no more samples in any channel
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ch = 0; ch < num_channels; ch++) {
|
||||||
|
sound_state_type state = &states[ch];
|
||||||
|
sound_type snd = getsound(getelement(nyx_result, ch));
|
||||||
// Copy and scale the samples
|
// Copy and scale the samples
|
||||||
for (i = 0; i < cnt; i++) {
|
for (int i = 0; i < togo; i++) {
|
||||||
buffer[i] = block->samples[i] * snd->scale;
|
buffer[i] = *(state->samps++) * (float) snd->scale;
|
||||||
}
|
}
|
||||||
|
state->cnt -= togo;
|
||||||
result = callback((float *)buffer, ch,
|
// TODO: What happens here when we don't know the total length,
|
||||||
totals[ch], cnt, lens[ch] ? lens[ch] : cnt, userdata);
|
// i.e. nyx_input_length == 0? Should we pass total+togo instead?
|
||||||
|
result = callback(buffer, ch, total, togo, nyx_input_length, userdata);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
result = -1;
|
result = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
totals[ch] += cnt;
|
|
||||||
}
|
}
|
||||||
|
total += togo;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ch = 0 ; ch < num_channels; ch++) {
|
nyx_result = NULL; // unreference sound array so GC can free it
|
||||||
sound_unref(snds[ch]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will unwind the xlisp context and restore internals to a point just
|
// This will unwind the xlisp context and restore internals to a point just
|
||||||
// before we issued our xlbegin() above. This is important since the internal
|
// before we issued our xlbegin() above. This is important since the internal
|
||||||
@ -1069,25 +1121,17 @@ int nyx_get_audio(nyx_audio_callback callback, void *userdata)
|
|||||||
finish:
|
finish:
|
||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lens) {
|
if (states) {
|
||||||
free(lens);
|
free(states);
|
||||||
}
|
|
||||||
|
|
||||||
if (totals) {
|
|
||||||
free(totals);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snds) {
|
|
||||||
free(snds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
|
||||||
printf("\nnyx_get_audio after\n");
|
stdputstr("\nnyx_get_audio after\n");
|
||||||
xmem();
|
xmem();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@ using namespace std;
|
|||||||
// #include "trace.h" -- only needed for debugging
|
// #include "trace.h" -- only needed for debugging
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
|
#define ALGDBG(x) ;
|
||||||
|
// #define ALGDBG(x) x; // turn on some printing for tracing/debugging
|
||||||
|
|
||||||
#define STREQL(x, y) (strcmp(x, y) == 0)
|
#define STREQL(x, y) (strcmp(x, y) == 0)
|
||||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||||
#define ROUND(x) ((int) ((x) + 0.5))
|
#define ROUND(x) ((int) ((x) + 0.5))
|
||||||
@ -592,11 +595,11 @@ Alg_note::Alg_note(Alg_note_ptr note)
|
|||||||
*this = *note; // copy all fields
|
*this = *note; // copy all fields
|
||||||
// parameters is now a shared pointer. We need to copy the
|
// parameters is now a shared pointer. We need to copy the
|
||||||
// parameters
|
// parameters
|
||||||
Alg_parameters_ptr next_param_ptr = parameters;
|
Alg_parameters_ptr next_parm_ptr = parameters;
|
||||||
while (next_param_ptr) {
|
while (next_parm_ptr) {
|
||||||
Alg_parameters_ptr new_params = new Alg_parameters(next_param_ptr->next);
|
Alg_parameters_ptr new_parms = new Alg_parameters(next_parm_ptr->next);
|
||||||
new_params->parm.copy(&(next_param_ptr->parm)); // copy the attribute and value
|
new_parms->parm.copy(&(next_parm_ptr->parm)); // copy the attribute and value
|
||||||
next_param_ptr = new_params->next;
|
next_parm_ptr = new_parms->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,7 +616,7 @@ Alg_note::~Alg_note()
|
|||||||
|
|
||||||
void Alg_note::show()
|
void Alg_note::show()
|
||||||
{
|
{
|
||||||
printf("Alg_note: time %g, chan %ld, dur %g, key %ld, "
|
printf("Alg_note: time %g, chan %d, dur %g, key %d, "
|
||||||
"pitch %g, loud %g, attributes ",
|
"pitch %g, loud %g, attributes ",
|
||||||
time, chan, dur, key, pitch, loud);
|
time, chan, dur, key, pitch, loud);
|
||||||
Alg_parameters_ptr parms = parameters;
|
Alg_parameters_ptr parms = parameters;
|
||||||
@ -1370,17 +1373,26 @@ void Alg_seq::serialize(void **buffer, long *bytes)
|
|||||||
ser_write_buf.init_for_write();
|
ser_write_buf.init_for_write();
|
||||||
serialize_seq();
|
serialize_seq();
|
||||||
*buffer = ser_write_buf.to_heap(bytes);
|
*buffer = ser_write_buf.to_heap(bytes);
|
||||||
|
ALGDBG(int chksum = 0; unsigned char *data = (unsigned char *) *buffer);
|
||||||
|
// not a reliable checksum, just a sanity check:
|
||||||
|
ALGDBG(for (int i = 0; i < *bytes; i++) chksum += data[i]);
|
||||||
|
ALGDBG(printf("Alg_seq::serialize %ld bytes, chksum %d\n", *bytes, chksum));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// make sure we can write at least needed more bytes into buffer
|
||||||
void Serial_write_buffer::check_buffer(long needed)
|
void Serial_write_buffer::check_buffer(long needed)
|
||||||
{
|
{
|
||||||
if (len < (ptr - buffer) + needed) { // do we need more space?
|
needed += (ptr - buffer);
|
||||||
|
assert(needed > 0); // did we overflow?
|
||||||
|
if (len < needed) { // do we need more space?
|
||||||
long new_len = len * 2; // exponential growth is important
|
long new_len = len * 2; // exponential growth is important
|
||||||
|
assert(new_len >= 0); // did we overflow?
|
||||||
// initially, length is zero, so bump new_len to a starting value
|
// initially, length is zero, so bump new_len to a starting value
|
||||||
if (new_len == 0) new_len = 1024;
|
if (new_len == 0) new_len = 1024;
|
||||||
// make sure new_len is as big as needed
|
// make sure new_len is as big as needed
|
||||||
if (needed > new_len) new_len = needed;
|
if (needed > new_len) new_len = needed;
|
||||||
|
assert(new_len <= 0x7FFFFFFF); // we use 32-bit offsets
|
||||||
char *new_buffer = new char[new_len]; // allocate space
|
char *new_buffer = new char[new_len]; // allocate space
|
||||||
ptr = new_buffer + (ptr - buffer); // relocate ptr to new buffer
|
ptr = new_buffer + (ptr - buffer); // relocate ptr to new buffer
|
||||||
if (len > 0) { // we had a buffer already
|
if (len > 0) { // we had a buffer already
|
||||||
@ -1430,7 +1442,8 @@ void Alg_seq::serialize_seq()
|
|||||||
track(i)->serialize_track();
|
track(i)->serialize_track();
|
||||||
}
|
}
|
||||||
// do not include ALGS, include padding at end
|
// do not include ALGS, include padding at end
|
||||||
ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset);
|
ser_write_buf.store_int32(length_offset,
|
||||||
|
ser_write_buf.get_posn() - length_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1453,6 +1466,7 @@ void Alg_track::serialize_track()
|
|||||||
ser_write_buf.check_buffer(24);
|
ser_write_buf.check_buffer(24);
|
||||||
Alg_event *event = (*this)[j];
|
Alg_event *event = (*this)[j];
|
||||||
ser_write_buf.set_int32(event->get_selected());
|
ser_write_buf.set_int32(event->get_selected());
|
||||||
|
assert(event->get_type() == 'n' || event->get_type() == 'u');
|
||||||
ser_write_buf.set_int32(event->get_type());
|
ser_write_buf.set_int32(event->get_type());
|
||||||
ser_write_buf.set_int32(event->get_identifier());
|
ser_write_buf.set_int32(event->get_identifier());
|
||||||
ser_write_buf.set_int32(event->chan);
|
ser_write_buf.set_int32(event->chan);
|
||||||
@ -1472,7 +1486,7 @@ void Alg_track::serialize_track()
|
|||||||
parms = parms->next;
|
parms = parms->next;
|
||||||
parm_num++;
|
parm_num++;
|
||||||
}
|
}
|
||||||
ser_write_buf.store_long(parm_num_offset, parm_num);
|
ser_write_buf.store_int32(parm_num_offset, parm_num);
|
||||||
} else {
|
} else {
|
||||||
assert(event->is_update());
|
assert(event->is_update());
|
||||||
Alg_update *update = (Alg_update *) event;
|
Alg_update *update = (Alg_update *) event;
|
||||||
@ -1482,7 +1496,8 @@ void Alg_track::serialize_track()
|
|||||||
ser_write_buf.pad();
|
ser_write_buf.pad();
|
||||||
}
|
}
|
||||||
// write length, not including ALGT, including padding at end
|
// write length, not including ALGT, including padding at end
|
||||||
ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset);
|
ser_write_buf.store_int32(length_offset,
|
||||||
|
ser_write_buf.get_posn() - length_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1493,7 +1508,6 @@ void Alg_track::serialize_parameter(Alg_parameter *parm)
|
|||||||
long len = strlen(parm->attr_name()) + 8;
|
long len = strlen(parm->attr_name()) + 8;
|
||||||
ser_write_buf.check_buffer(len);
|
ser_write_buf.check_buffer(len);
|
||||||
ser_write_buf.set_string(parm->attr_name());
|
ser_write_buf.set_string(parm->attr_name());
|
||||||
ser_write_buf.pad();
|
|
||||||
switch (parm->attr_type()) {
|
switch (parm->attr_type()) {
|
||||||
case 'r':
|
case 'r':
|
||||||
ser_write_buf.check_buffer(8);
|
ser_write_buf.check_buffer(8);
|
||||||
@ -1523,6 +1537,11 @@ void Alg_track::serialize_parameter(Alg_parameter *parm)
|
|||||||
Alg_track *Alg_track::unserialize(void *buffer, long len)
|
Alg_track *Alg_track::unserialize(void *buffer, long len)
|
||||||
{
|
{
|
||||||
assert(len > 8);
|
assert(len > 8);
|
||||||
|
// should match serialized checksum (just for sanity checks):
|
||||||
|
ALGDBG(int chksum = 0; unsigned char *data = (unsigned char *) buffer);
|
||||||
|
ALGDBG(for (int i = 0; i < len; i++) chksum += data[i]);
|
||||||
|
ALGDBG(printf("Alg_track::unserialize %ld bytes, chksum %d\n",
|
||||||
|
len, chksum));
|
||||||
ser_read_buf.init_for_read(buffer, len);
|
ser_read_buf.init_for_read(buffer, len);
|
||||||
bool alg = ser_read_buf.get_char() == 'A' &&
|
bool alg = ser_read_buf.get_char() == 'A' &&
|
||||||
ser_read_buf.get_char() == 'L' &&
|
ser_read_buf.get_char() == 'L' &&
|
||||||
@ -1605,7 +1624,7 @@ void Alg_track::unserialize_track()
|
|||||||
(ser_read_buf.get_char() == 'G') &&
|
(ser_read_buf.get_char() == 'G') &&
|
||||||
(ser_read_buf.get_char() == 'T');
|
(ser_read_buf.get_char() == 'T');
|
||||||
assert(algt);
|
assert(algt);
|
||||||
long offset = ser_read_buf.get_posn(); // stored length does not include 'ALGT'
|
long offset = ser_read_buf.get_posn(); // length does not include 'ALGT'
|
||||||
long bytes = ser_read_buf.get_int32();
|
long bytes = ser_read_buf.get_int32();
|
||||||
assert(bytes <= ser_read_buf.get_len() - offset);
|
assert(bytes <= ser_read_buf.get_len() - offset);
|
||||||
units_are_seconds = (bool) ser_read_buf.get_int32();
|
units_are_seconds = (bool) ser_read_buf.get_int32();
|
||||||
@ -1616,7 +1635,7 @@ void Alg_track::unserialize_track()
|
|||||||
ser_read_buf.check_input_buffer(24);
|
ser_read_buf.check_input_buffer(24);
|
||||||
long selected = ser_read_buf.get_int32();
|
long selected = ser_read_buf.get_int32();
|
||||||
char type = (char) ser_read_buf.get_int32();
|
char type = (char) ser_read_buf.get_int32();
|
||||||
long key = ser_read_buf.get_int32();
|
int32_t key = ser_read_buf.get_int32();
|
||||||
long channel = ser_read_buf.get_int32();
|
long channel = ser_read_buf.get_int32();
|
||||||
double time = ser_read_buf.get_double();
|
double time = ser_read_buf.get_double();
|
||||||
if (type == 'n') {
|
if (type == 'n') {
|
||||||
@ -1627,12 +1646,12 @@ void Alg_track::unserialize_track()
|
|||||||
Alg_note *note =
|
Alg_note *note =
|
||||||
create_note(time, channel, key, pitch, loud, dur);
|
create_note(time, channel, key, pitch, loud, dur);
|
||||||
note->set_selected(selected != 0);
|
note->set_selected(selected != 0);
|
||||||
long param_num = ser_read_buf.get_int32();
|
long parm_num = ser_read_buf.get_int32();
|
||||||
int j;
|
int j;
|
||||||
// this builds a list of parameters in the correct order
|
// this builds a list of parameters in the correct order
|
||||||
// (although order shouldn't matter)
|
// (although order shouldn't matter)
|
||||||
Alg_parameters_ptr *list = ¬e->parameters;
|
Alg_parameters_ptr *list = ¬e->parameters;
|
||||||
for (j = 0; j < param_num; j++) {
|
for (j = 0; j < parm_num; j++) {
|
||||||
*list = new Alg_parameters(NULL);
|
*list = new Alg_parameters(NULL);
|
||||||
unserialize_parameter(&((*list)->parm));
|
unserialize_parameter(&((*list)->parm));
|
||||||
list = &((*list)->next);
|
list = &((*list)->next);
|
||||||
@ -1957,7 +1976,7 @@ void Alg_track::insert_silence(double t, double len)
|
|||||||
|
|
||||||
|
|
||||||
Alg_event_list *Alg_track::find(double t, double len, bool all,
|
Alg_event_list *Alg_track::find(double t, double len, bool all,
|
||||||
long channel_mask, long event_type_mask)
|
int32_t channel_mask, int32_t event_type_mask)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Alg_event_list *list = new Alg_event_list(this);
|
Alg_event_list *list = new Alg_event_list(this);
|
||||||
@ -3215,8 +3234,8 @@ void Alg_seq::clear(double start, double len, bool all)
|
|||||||
|
|
||||||
|
|
||||||
Alg_event_list_ptr Alg_seq::find_in_track(int track_num, double t, double len,
|
Alg_event_list_ptr Alg_seq::find_in_track(int track_num, double t, double len,
|
||||||
bool all, long channel_mask,
|
bool all, int32_t channel_mask,
|
||||||
long event_type_mask)
|
int32_t event_type_mask)
|
||||||
{
|
{
|
||||||
return track(track_num)->find(t, len, all, channel_mask, event_type_mask);
|
return track(track_num)->find(t, len, all, channel_mask, event_type_mask);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ public:
|
|||||||
union {
|
union {
|
||||||
double r;// real
|
double r;// real
|
||||||
const char *s; // string
|
const char *s; // string
|
||||||
long i; // integer
|
int64_t i; // integer -- 64 bit for 32/64-bit compatibility
|
||||||
bool l; // logical
|
bool l; // logical
|
||||||
const char *a; // symbol (atom)
|
const char *a; // symbol (atom)
|
||||||
}; // anonymous union
|
}; // anonymous union
|
||||||
@ -162,7 +162,8 @@ public:
|
|||||||
// insert string will copy string to heap
|
// insert string will copy string to heap
|
||||||
static void insert_string(Alg_parameters **list, const char *name,
|
static void insert_string(Alg_parameters **list, const char *name,
|
||||||
const char *s);
|
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_logical(Alg_parameters **list, const char *name, bool l);
|
||||||
static void insert_atom(Alg_parameters **list, const char *name,
|
static void insert_atom(Alg_parameters **list, const char *name,
|
||||||
const char *s);
|
const char *s);
|
||||||
@ -190,11 +191,11 @@ typedef class Alg_event {
|
|||||||
protected:
|
protected:
|
||||||
bool selected;
|
bool selected;
|
||||||
char type; // 'e' event, 'n' note, 'u' update
|
char type; // 'e' event, 'n' note, 'u' update
|
||||||
long key; // note identifier
|
int32_t key; // note identifier -- fixed at 32 bits
|
||||||
static const char* description; // static buffer for debugging (in Alg_event)
|
static const char* description; // static buffer for debugging
|
||||||
public:
|
public:
|
||||||
double time;
|
double time;
|
||||||
long chan;
|
int32_t chan; // generalization of MIDI channels -- fixed at 32 bits
|
||||||
virtual void show() = 0;
|
virtual void show() = 0;
|
||||||
// Note: there is no Alg_event() because Alg_event is an abstract class.
|
// 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_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
|
// For midi, the identifier is the key number (pitch). The identifier
|
||||||
// does not have to represent pitch; it's main purpose is to identify
|
// does not have to represent pitch; it's main purpose is to identify
|
||||||
// notes so that they can be named by subsequent update events.
|
// 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
|
// In all of these set_ methods, strings are owned by the caller and
|
||||||
// copied as necessary by the callee. For notes, an attribute/value
|
// copied as necessary by the callee. For notes, an attribute/value
|
||||||
// pair is added to the parameters list. For updates, the single
|
// 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_string_value(const char *attr, const char *value);
|
||||||
void set_real_value(const char *attr, double value);
|
void set_real_value(const char *attr, double value);
|
||||||
void set_logical_value(const char *attr, bool 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);
|
void set_atom_value(const char *attr, const char *atom);
|
||||||
|
|
||||||
// Some note methods. These fail (via assert()) if this is not a note:
|
// 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
|
bool has_attribute(const char *attr); // test if note has attribute/value pair
|
||||||
char get_attribute_type(const char *attr); // get the associated type:
|
char get_attribute_type(const char *attr); // get the associated type:
|
||||||
// 's' = string,
|
// '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
|
// 'a' = atom (char *), a unique string stored in Alg_seq
|
||||||
// get the string value
|
// get the string value
|
||||||
const char *get_string_value(const char *attr, const char *value = NULL);
|
const char *get_string_value(const char *attr, const char *value = NULL);
|
||||||
@ -255,7 +258,7 @@ public:
|
|||||||
// get the logical value
|
// get the logical value
|
||||||
bool get_logical_value(const char *attr, bool value = false);
|
bool get_logical_value(const char *attr, bool value = false);
|
||||||
// get the integer value
|
// 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
|
// get the atom value
|
||||||
const char *get_atom_value(const char *attr, const char *value = NULL);
|
const char *get_atom_value(const char *attr, const char *value = NULL);
|
||||||
void delete_attribute(const char *attr); // delete an attribute/value pair
|
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)
|
const char *get_attribute(); // get the update's attribute (string)
|
||||||
char get_update_type(); // get the update's type: 's' = 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
|
// 'a' = atom (char *), a unique string stored in Alg_seq
|
||||||
const 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.
|
// Notes: Caller does not own the return value. Do not modify.
|
||||||
// Do not use after underlying Alg_seq is modified.
|
// Do not use after underlying Alg_seq is modified.
|
||||||
double get_real_value(); // get the update's real value
|
double get_real_value(); // get the update's real value
|
||||||
bool get_logical_value(); // get the update's logical 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
|
const char *get_atom_value(); // get the update's atom value
|
||||||
// Notes: Caller does not own the return value. Do not modify.
|
// Notes: Caller does not own the return value. Do not modify.
|
||||||
// The return value's lifetime is forever.
|
// The return value's lifetime is forever.
|
||||||
@ -521,6 +524,25 @@ public:
|
|||||||
} *Alg_time_map_ptr;
|
} *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_buffer is an abstract class with common elements of
|
||||||
// Serial_read_buffer and Serial_write_buffer
|
// Serial_read_buffer and Serial_write_buffer
|
||||||
class Serial_buffer {
|
class Serial_buffer {
|
||||||
@ -549,10 +571,12 @@ public:
|
|||||||
// does nothing.
|
// does nothing.
|
||||||
virtual ~Serial_read_buffer() { }
|
virtual ~Serial_read_buffer() { }
|
||||||
#if defined(_WIN32)
|
#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: 546) // cast to int is OK, we only want low 7 bits
|
||||||
#pragma warning(disable: 4311) // type cast pointer to long warning
|
#pragma warning(disable: 4311) // type cast pointer to long warning
|
||||||
#endif
|
#endif
|
||||||
void get_pad() { while (((long) ptr) & 7) ptr++; }
|
void get_pad() { while (((size_t) ptr) & 3) ptr++; }
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#pragma warning(default: 4311 546)
|
#pragma warning(default: 4311 546)
|
||||||
#endif
|
#endif
|
||||||
@ -566,11 +590,16 @@ public:
|
|||||||
}
|
}
|
||||||
char get_char() { return *ptr++; }
|
char get_char() { return *ptr++; }
|
||||||
void unget_chars(int n) { ptr -= n; } // undo n get_char() calls
|
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; }
|
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;
|
const char *get_string() { char *s = ptr; char *fence = buffer + len;
|
||||||
|
ptr += strlen(s);
|
||||||
assert(ptr < fence);
|
assert(ptr < fence);
|
||||||
while (*ptr++) assert(ptr < fence);
|
while (*ptr++) assert(ptr < fence);
|
||||||
get_pad();
|
get_pad();
|
||||||
@ -592,9 +621,9 @@ typedef class Serial_write_buffer: public Serial_buffer {
|
|||||||
}
|
}
|
||||||
void init_for_write() { ptr = buffer; }
|
void init_for_write() { ptr = buffer; }
|
||||||
// store_long writes a long at a given offset
|
// store_long writes a long at a given offset
|
||||||
void store_long(long offset, long value) {
|
void store_int32(long offset, int32_t value) {
|
||||||
assert(offset <= get_posn() - 4);
|
assert(offset <= get_posn() - sizeof(value));
|
||||||
long *loc = (long *) (buffer + offset);
|
int32_t *loc = (int32_t *) (buffer + offset);
|
||||||
*loc = value;
|
*loc = value;
|
||||||
}
|
}
|
||||||
void check_buffer(long needed);
|
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
|
// two brackets surpress a g++ warning, because this is an
|
||||||
// assignment operator inside a test.
|
// assignment operator inside a test.
|
||||||
while ((*ptr++ = *s++)) assert(ptr < fence);
|
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
|
// 4311 is type cast pointer to long warning
|
||||||
// 4312 is type cast long to pointer warning
|
// 4312 is type cast long to pointer warning
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#pragma warning(disable: 4311 4312)
|
#pragma warning(disable: 4311 4312)
|
||||||
#endif
|
#endif
|
||||||
assert((char *)(((long) (ptr + 7)) & ~7) <= fence);
|
assert((char *)(((size_t) (ptr + 3)) & ~3) <= fence);
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#pragma warning(default: 4311 4312)
|
#pragma warning(default: 4311 4312)
|
||||||
#endif
|
#endif
|
||||||
pad(); }
|
pad(); }
|
||||||
void set_int32(long v) { *((long *) ptr) = v; ptr += 4; }
|
void set_int32(int32_t v) { *((int32_t *) ptr) = v; ptr += 4; }
|
||||||
void set_double(double v) { *((double *) ptr) = v; ptr += 8; }
|
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_float(float v) { *((float *) ptr) = v; ptr += 4; }
|
||||||
void set_char(char v) { *ptr++ = v; }
|
void set_char(char v) { *ptr++ = v; }
|
||||||
#if defined(_WIN32)
|
#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
|
#pragma warning(disable: 4311) // type cast pointer to long warning
|
||||||
#endif
|
#endif
|
||||||
void pad() { while (((long) ptr) & 7) set_char(0); }
|
void pad() { while (((size_t) ptr) & 3) set_char(0); }
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#pragma warning(default: 4311 546)
|
#pragma warning(default: 4311 546)
|
||||||
#endif
|
#endif
|
||||||
@ -640,10 +676,10 @@ typedef class Alg_track : public Alg_event_list {
|
|||||||
protected:
|
protected:
|
||||||
Alg_time_map *time_map;
|
Alg_time_map *time_map;
|
||||||
bool units_are_seconds;
|
bool units_are_seconds;
|
||||||
char *get_string(char **p, long *b);
|
// char *get_string(char **p, long *b); -- these seem to be orphaned
|
||||||
long get_int32(char **p, long *b);
|
// int32_t get_int32(char **p, long *b); -- declarations. Maybe they
|
||||||
double get_double(char **p, long *b);
|
// double get_double(char **p, long *b); -- were intended for
|
||||||
float get_float(char **p, long *b);
|
// float get_float(char **p, long *b); -- serialization. Delete them?
|
||||||
static Serial_read_buffer ser_read_buf;
|
static Serial_read_buffer ser_read_buf;
|
||||||
static Serial_write_buffer ser_write_buf;
|
static Serial_write_buffer ser_write_buf;
|
||||||
void serialize_parameter(Alg_parameter *parm);
|
void serialize_parameter(Alg_parameter *parm);
|
||||||
@ -804,9 +840,11 @@ public:
|
|||||||
// somewhere else. Part of the mask allows us to search for
|
// somewhere else. Part of the mask allows us to search for
|
||||||
// selected events. If this is an Alg_seq, search all tracks
|
// selected events. If this is an Alg_seq, search all tracks
|
||||||
// (otherwise, call track[i].find())
|
// (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,
|
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; }
|
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 clear_track(int track_num, double start, double len, bool all);
|
||||||
void silence_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,
|
Alg_event_list_ptr find_in_track(int track_num, double t, double len,
|
||||||
bool all, long channel_mask,
|
bool all, int32_t channel_mask,
|
||||||
long event_type_mask);
|
int32_t event_type_mask);
|
||||||
|
|
||||||
// find index of first score event after time
|
// find index of first score event after time
|
||||||
long seek_time(double time, int track_num);
|
long seek_time(double time, int track_num);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user