File: seqwrite.c

package info (click to toggle)
audacity 2.0.6-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 80,076 kB
  • sloc: cpp: 192,859; ansic: 158,072; sh: 34,021; python: 24,248; lisp: 7,495; makefile: 3,667; xml: 573; perl: 31; sed: 16
file content (282 lines) | stat: -rw-r--r-- 9,128 bytes parent folder | download | duplicates (13)
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
/* seqwrite -- write a seq in Adagio format to a file */
/***************************************************************************
*       Change Log
*  Date | Change
*-----------+--------------------------------------------------------------
* 11-Mar-94 | Created Change Log
* 11-Mar-94 | PLu : Added private to function defs.
* 28-Apr-03 |  DM : changed for portability, true->TRUE, false->FALSE
****************************************************************************/

#include "switches.h"

#include <stdio.h>

#include "cext.h"
#include "midifns.h"
#include "timebase.h"
#include "seq.h"
#include "seqwrite.h"
#include "userio.h"
#include "record.h"

private boolean next_event_time();
private void write_event();
private void write_velocity(FILE *f, int velocity);
private void write_voice();
private void write_rest(FILE *f, event_type ev, boolean abs_flag);
private void write_time();

private boolean clock_started;
private long clock_half_tick;
private int new_tempo;
/* non-zero indicates a pending tempo change... */
private time_type tempo_change_at;

private int macro_count;
private int call_count;
private int deframp_count;
private int seti_count;

private int last_velocity;
private int last_voice = seq_dflt_voice;


/* next_event_time -- get the time of the next event */
/*
 * NOTE: clock events are ignored (unless this is the first clock event)
 */
private boolean next_event_time(event, next_time)
  event_type event;
  time_type *next_time;
{
    while (event) {
        if (vc_ctrl(event->nvoice) == ESC_CTRL &&
            event->value == CLOCK_VALUE && 
            clock_started) {
            /* this is a clock event, ignore it: */
            event = event->next;
        } else {
            *next_time = event->ntime;
            return TRUE;
        }
    }
    return FALSE;
}


/* seq_write -- write a seq to a file */
/*
 * NOTE: if abs_flag, then write using absolute times ('T'), otherwise use
 *  relative timing ('N').  Also, only selected channels are written.
 */
void seq_write(seq_type seq, FILE *f, boolean abs_flag)
{
    event_type ev = seq_events(seq);

    last_velocity = seq_dflt_loud;
    last_voice = seq_dflt_voice;

    fprintf(f, "!MSEC\n");
    clock_started = FALSE;
    tempo_change_at = 0;

    macro_count = 0;
    call_count = 0;
    deframp_count = 0;
    seti_count = 0;

    while (ev) {
        write_event(seq, ev, f, abs_flag);
        ev = ev->next;
    }
    if (macro_count) gprintf(TRANS, "%d macros ignored.\n", macro_count);
    if (call_count) gprintf(TRANS, "%d calls ignored.\n", call_count);
    if (deframp_count) gprintf(TRANS, "%d deframps ignored.\n", deframp_count);
    if (seti_count) gprintf(TRANS, "%d setis ignored.\n", seti_count);
}


private char ctrl_letter[] = "?KMOXYZ";

/* write_event -- write a single event to a file */
/**/
private void write_event(seq, event, f, abs_flag)
  seq_type seq;
  event_type event;
  FILE *f;
  boolean abs_flag;
{
    int voice = vc_voice(event->nvoice);

    /* process all current (and earlier) events */
    if (is_note(event)) {       /*** a note or rest ***/
        /* if this note is not a rest, write it */
        if (event->value != NO_PITCH &&
                  (seq_channel_mask(seq) &
                   (1 << (voice - 1)))) {
            write_pitch(f, event->value);
            fprintf(f, " U%ld ", event->u.note.ndur >> 8);
            write_velocity(f, (int) (event->u.note.ndur & 0xFF));
            write_voice(f, voice);
            write_time(f, event, abs_flag);
        }
    } else {            /*** a control command ***/
        switch (vc_ctrl(event->nvoice)) {
          case PSWITCH_CTRL:
          case MODWHEEL_CTRL:
          case TOUCH_CTRL:
          case VOLUME_CTRL:
          case BEND_CTRL:
            fprintf(f, "%c%d ", ctrl_letter[vc_ctrl(event->nvoice)],
                                    event->value);
            write_voice(f, voice);
            write_time(f, event, abs_flag);
            break;
          case PROGRAM_CTRL:
            fprintf(f, "Z%d ", event->value + 1);
            write_voice(f, voice);
            write_time(f, event, abs_flag);
            break;
          case ESC_CTRL:
            switch (event->value) {
              case CALL_VALUE:
                call_count++;
                write_rest(f, event, abs_flag);
                /* !call's are not written because there isn't enough
                 * information.  A future version of seq should store
                 * the hash table entry instead of the address of the
                 * routine (then we could get string name of the call)
                 * and the number of arguments.
                 */
                break;
              case CLOCK_VALUE:
                /* design for !clock: for absolute (absflag) files, put the
                   clocks (if any) at the end where they can be edited out
                   easily.  For relative files, keep the clocks in-line.
                   On each clock, write a !tempo command inferred by the 
                   clock and followed by the !clock.  Because the clock
                   event comes before the actual tempo change, the chnage
                   must be delayed by a half tick except for the first one.
                 */
                if (abs_flag) break;
                new_tempo = (2500L << 16) / event->u.clock.ticksize;
                if (clock_started) {
                    tempo_change_at = event->ntime + clock_half_tick;
                } else {
                    fprintf(f, "!tempo %d\n", new_tempo);
                    fprintf(f, "!clock\n");
                    clock_started = TRUE;
                }
                clock_half_tick = (event->u.clock.ticksize) >> 17;
                break;
              case MACCTRL_VALUE:
                fprintf(f, "~%d(%d) ", event->u.macctrl.ctrl_number,
                                       event->u.macctrl.value);
                write_voice(f, voice);
                write_time(f, event, abs_flag);
                break;
              case MACRO_VALUE: 
                macro_count++;
                write_rest(f, event, abs_flag);
                /* macros are not written because there isn't enough
                 * information.  A future version of seq should store
                 * the number of arguments in the event, or better yet,
                 * in the definition.  Send complaints to RBD!
                 */
                break;
              case CTRLRAMP_VALUE:
                fprintf(f, "!ramp ~%d(%d) ~%d(%d) U%d U%d ",
                        event->u.ramp.ctrl, event->u.ramp.u.ctrl.from_value,
                        event->u.ramp.ctrl, event->u.ramp.u.ctrl.to_value,
                        (int)event->u.ramp.step,
                        (int)event->u.ramp.dur);
                write_voice(f, voice);
                write_time(f, event, abs_flag);
                break;
              case DEFRAMP_VALUE:
                deframp_count++;
                write_rest(f, event, abs_flag);
                /* See MACRO_VALUE above for why this isn't implemented. */
                break;
              case SETI_VALUE:
                seti_count++;
                write_rest(f, event, abs_flag);
                /* !seti and !setv are not implemented -- a future version
                 * of seq should save more information so we can reconstruct
                 * the Adagio source command.
                 */
                break;
              default:
                gprintf(TRANS, "unexpected ESC_CTRL value\n");
                break;
            }
            break;
          default:
            gprintf(TRANS, "unexpected seq data\n");
            break;
        }
    }
}


/* write_rest -- write a rest (in place of an event) */
/**/
private void write_rest(FILE *f, event_type ev, boolean abs_flag)
{
    fprintf(f, "R ");
    write_time(f, ev, abs_flag);
}


/* write_time -- write the final field on the line with N or T command */
/**/
private void write_time(f, event, abs_flag)
  FILE *f;
  event_type event;
  boolean abs_flag;
{
    time_type next_time;

    if (abs_flag) {
        fprintf(f, "T%ld\n", event->ntime);
        return;
    }

    if (next_event_time(event->next, &next_time)) {
        if (tempo_change_at && (next_time >= tempo_change_at)) {
            fprintf(f, "N%ld\n!TEMPO %d\n!CLOCK\nR U%ld\n", 
                        tempo_change_at - event->ntime,
                        new_tempo, next_time - tempo_change_at);
            tempo_change_at = 0;
        } else {
            fprintf(f, "N%ld\n", next_time - event->ntime);
        }
    } else {
        fprintf(f, "\n");
    }
}


/* write_velocity -- write the velocity field */
/**/
private void write_velocity(FILE *f, int velocity)
{
    if (last_velocity != velocity) {
        last_velocity = velocity;
        fprintf(f, "L%d ", velocity);
    }
}


/* write_voice -- write the voice field */
/**/
private void write_voice(f, voice)
  FILE *f;
  int voice;
{
    if (last_voice != voice) {
        last_voice = voice;
        fprintf(f, "V%d ", voice);
    }
}