-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathallegrowr.cpp
183 lines (174 loc) · 6.21 KB
/
allegrowr.cpp
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
// allegrowr.cpp -- write sequence to an Allegro file (text)
#include "assert.h"
#include "stdlib.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <errno.h>
#include <string>
#include "memory.h"
using namespace std;
#include "strparse.h"
#include "allegro.h"
// Note about precision: %g prints 6 significant digits. For 1ms precision,
// the maximum magnitude is 999.999, i.e. 1000s < 17minutes. For anything
// over 1000s, time in seconds will be printed with 10ms precision, which
// is not good. Therefore, times and durations are printed as %.4d, which
// gives 100us precision.
// The following define allows you to change this decision:
/* #define TIMFMT "%.4d" */
#define TIMPREC 4
#define TIMFMT fixed << setprecision(TIMPREC)
#define GFMT resetiosflags(ios::floatfield) << setprecision(6)
void parameter_print(ostream &file, Alg_parameter_ptr p)
{
file << " -" << p->attr_name() << ":";
switch (p->attr_type()) {
case 'a':
file << "'" << alg_attr_name(p->a) << "'";
break;
case 'i':
file << p->i;
break;
case 'l':
file << (p->l ? "true" : "false");
break;
case 'r':
file << p->r;
break;
case 's': {
string str;
string_escape(str, p->s, "\"");
file << str;
break;
}
}
}
Alg_event_ptr Alg_seq::write_track_name(ostream &file, int n,
Alg_events &events)
// write #track <n> <trackname-or-sequencename>
// if we write the name on the "#track" line, then we do *not* want
// to write again as an update: "-seqnames:"Jordu", so if we do
// find a name and write it, return a pointer to it so the track
// writer knows what update (if any) to skip
{
Alg_event_ptr e = NULL; // e is the result, default is NULL
file << "#track " << n;
const char *attr = symbol_table.insert_string(
n == 0 ? "seqnames" : "tracknames");
// search for name in events with timestamp of 0
for (int i = 0; i < events.length(); i++) {
Alg_event_ptr ue = events[i];
if (ue->time > 0) break;
if (ue->is_update()) {
Alg_update_ptr u = (Alg_update_ptr) ue;
if (u->parameter.attr == attr) {
file << " " << u->parameter.s;
e = ue; // return the update event we found
break;
}
}
}
file << endl; // end of line containing #track [<name>]
return e; // return parameter event with name if one was found
}
void Alg_seq::write(ostream &file, bool in_secs, double offset)
{
int i, j;
if (in_secs) convert_to_seconds();
else convert_to_beats();
file << "#offset " << offset << endl;
Alg_event_ptr update_to_skip = write_track_name(file, 0, track_list[0]);
Alg_beats &beats = time_map->beats;
for (i = 0; i < beats.len - 1; i++) {
Alg_beat_ptr b = &(beats[i]);
if (in_secs) {
file << "T" << TIMFMT << b->time;
} else {
file << "TW" << TIMFMT << b->beat / 4;
}
double tempo = (beats[i + 1].beat - b->beat) /
(beats[i + 1].time - beats[i].time);
file << " -tempor:" << GFMT << tempo * 60 << "\n";
}
if (time_map->last_tempo_flag) { // we have final tempo:
Alg_beat_ptr b = &(beats[beats.len - 1]);
if (in_secs) {
file << "T" << TIMFMT << b->time;
} else {
file << "TW" << TIMFMT << b->beat / 4;
}
file << " -tempor:" << GFMT << time_map->last_tempo * 60.0 << "\n";
}
// write the time signatures
for (i = 0; i < time_sig.length(); i++) {
Alg_time_sig &ts = time_sig[i];
double time = ts.beat;
if (in_secs) {
file << "T" << TIMFMT << time << " V- -timesig_numr:" <<
GFMT << ts.num << "\n";
file << "T" << TIMFMT << time << " V- -timesig_denr:" <<
GFMT << ts.den << "\n";
} else {
double wholes = ts.beat / 4;
file << "TW" << TIMFMT << wholes << " V- -timesig_numr:" <<
GFMT << ts.num << "\n";
file << "TW" << TIMFMT << wholes << " V- -timesig_denr:" <<
GFMT << ts.den << "\n";
}
}
for (j = 0; j < track_list.length(); j++) {
Alg_events ¬es = track_list[j];
if (j != 0) update_to_skip = write_track_name(file, j, notes);
// now write the notes at beat positions
for (i = 0; i < notes.length(); i++) {
Alg_event_ptr e = notes[i];
// if we already wrote this event as a track or sequence name,
// do not write it again
if (e == update_to_skip) continue;
double start = e->time;
if (in_secs) {
file << "T" << TIMFMT << start;
} else {
file << "TW" << TIMFMT << start / 4;
}
// write the channel as Vn or V-
if (e->chan == -1) file << " V-";
else file << " V" << e->chan;
// write the note or update data
if (e->is_note()) {
Alg_note_ptr n = (Alg_note_ptr) e;
double dur = n->dur;
file << " K" << n->get_identifier() <<
" P" << GFMT << n->pitch;
if (in_secs) {
file << " U" << TIMFMT << dur;
} else {
file << " Q" << TIMFMT << dur;
}
file << " L" << GFMT << n->loud;
Alg_parameters_ptr p = n->parameters;
while (p) {
parameter_print(file, &(p->parm));
p = p->next;
}
} else { // an update
assert(e->is_update());
Alg_update_ptr u = (Alg_update_ptr) e;
if (u->get_identifier() != -1) {
file << " K" << u->get_identifier();
}
parameter_print(file, &(u->parameter));
}
file << "\n";
}
}
}
bool Alg_seq::write(const char *filename, double offset)
{
ofstream file(filename);
if (file.fail()) return false;
write(file, units_are_seconds, offset);
file.close();
return true;
}