📄 seqwrite.c
字号:
/* 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); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -