📄 record.c
字号:
/* record.c -- keyboard to adagio recorder * Copyright 1989 Carnegie Mellon University * * the interface consists of three routines: * rec_init() -- initialization * rec_event(byte *data) -- called to insert (record) midi data, * -- returns FALSE if no more space * rec_final() -- called to finish up *//****************************************************************************** Change Log* Date | Change*-----------+-----------------------------------------------------------------* 27-Feb-86 | Created changelog* | Use pedal information when computing durations (code taken* | from transcribe.c)* 23-Mar-86 | Determine size of transcription when rec_init is called.* 21-May-86 | Major rewrite to use continuous controls (code taken * | from transcribe.c)* 1-Aug-87 | F.H. Changed rec_init() to new memory handling.* 17-Oct-88 | JCD : portable version.* 31-Jan-90 | GWL : cleaned up for LATTICE* 30-Jun-90 | RBD : further changes* 2-Apr-91 | JDW : further changes* 28-Apr-03 | DM : changed for portability; true->TRUE, false->FALSE*****************************************************************************/#include "switches.h"#include <stdio.h>#include <stdlib.h>#include "cext.h"#include "midifns.h"#include "userio.h"#include "midicode.h"#include "record.h"#include "cmdline.h"extern long space; /* how much space is left? */int debug_rec = FALSE; /* verbose debug flag for this module */long max_notes = -1L; /* -1 is flag that space must be allocated */time_type previous_time;/***************************************************************** data structure notes: the midi stream is stored as an array * of 4-byte records, each of which is either a time or midi* data. Midi data always begins with a control byte (high* order bit set), and it is assumed times are positive (high* order bit clear), so the two are easy to distinguish* IF THE COMPILER PUTS THESE BITS IN THE SAME PLACE. It looks* like the high order byte of the time lines up with the last* byte of a 4 byte array, so we will always set the high order* bit of the last array byte when the first 3 bytes are filled* with MIDI data. This is refered to as the "tag" bit.* WARNING: Lattice C longs are UNSIGNED, therefore always* positive. Test the high order bit with a mask.****************************************************************/#define MIDI_CMD_BIT 0x80#define HIGH_BIT 0x80000000#define istime(note) (!(((note)->when) & HIGH_BIT))typedef union note_struct { byte n[4]; long when;} *note_type, note_node;private note_type event_buff; /* pointer to allocated buffer */private note_type next; /* pointer to next entry in buffer */private note_type last; /* pointer to last entry in buffer */private int pile_ups; /* inner loop iteration count */private int max_pile_up; /* maximum of pile_ups */private boolean fixed_octave; /* used to avoid many error messages *//***************************************************************************** Routines local to this module****************************************************************************/private void bend_filter();private void byteorder();private void ctrl_filter();private int event_bend();private void filter();private long getdur();private long getnext();private char map_ctrl();private void output();/***************************************************************************** bend_filter* Inputs:* note_type note: the current note* note_type last: the last recorded event* long now: the current time* Effect:* remove pitch bend events in same 0.01 sec time slot* Implementation:* If the current event is a pitch bend that bends again* in the same time slot, make it a no-op by replacing it with* the time.****************************************************************************/private void bend_filter(note, last, now)note_type note; /* current note */note_type last; /* the last recorded event */long now; /* the current time */{ /* first see if there is another bend in this time * slot. */ note_type note2 = note + 1; while (note2 < last) { if (istime(note2) && (note2->when > now)) { break; /* new time slot */ } else if (note->n[0] == note2->n[0]) { note->when = now; return; /* found another bend */ } note2++; }}/***************************************************************************** byteorder* Effect: * check out assumptions about byte order and placement****************************************************************************/private void byteorder(){ note_node test_event; if ((sizeof(test_event) != 4) || (sizeof(test_event.when) != 4) || (sizeof(test_event.n[0]) != 1)) { gprintf(ERROR, "implementation error: size problem\n"); EXIT(1); } test_event.n[0] = 0x12; test_event.n[1] = 0x34; test_event.n[2] = 0x56; test_event.n[3] = 0x78; if ((test_event.when != 0x78563412) && (test_event.when != 0x12345678)) { gprintf(ERROR, "implementation error: layout problem\n"); EXIT(1); }}/***************************************************************************** ctrl_filter* Inputs:* note_type note: the current note* note_type last: the last recorded event* long now: the current time* Effect:* remove ctrl change events in same 0.01 sec time slot* Implementation:* If the current event is a control change that changes again* in the same time slot, make it a no-op by replacing it with* the time.****************************************************************************/private void ctrl_filter(note, last, now)note_type note; /* the current note */note_type last; /* the last recorded event */long now; /* the current time */{ /* see if there is another control change in this time * slot. */ note_type note2 = note+1; while (note2 < last) { if (istime(note2) && (note2->when > now)) { break; /* new time slot */ } else if ((note->n[0] == note2->n[0]) && (note->n[1] == note2->n[1])) { note->when = now; return; /* found another change */ } note2++; }}/***************************************************************************** event_bend* Inputs:* note_type note: pointer to a pitch bend event* Outputs:* returns int: an 8 bit pitch bend number****************************************************************************/private int event_bend(note)note_type note;{ return((int) (((note->n[1]) >> 6) + ((note->n[2]) << 1)));}/***************************************************************************** filter* Inputs:* note_type last: the last note recorded* Effect: allow only one control change per time slot (0.01 sec)* Implementation:* call ctrl_filter and bend_filter to overwrite control changes with* noop data (the current time is used as a noop)****************************************************************************/private void filter(last)note_type last;{ note_type note; /* loop control variable */ long now=0; /* last time seen */ int command; /* command pointed to by note */ for (note = event_buff; note <= last; note++) { if (istime(note)) { now = note->when; } else { command = note->n[0] & MIDI_CODE_MASK; if (command == MIDI_CTRL && note->n[1] == SUSTAIN) { /* do nothing */; } else if (command == MIDI_CTRL) { ctrl_filter(note, last, now); } else if (command == MIDI_TOUCH) { bend_filter(note, last, now); /* bend and touch use the */ } else if (command == MIDI_BEND) { /* same filter routines */ bend_filter(note, last, now); } } }}/***************************************************************************** getdur* Inputs:* int i: index of the note* note_type last: pointer to the last event recorded* int ped: TRUE if pedal is down at event i* long now: the time at event i* Outputs:* returns long: the duration of note i* Assumes:* assumes i is a note* Implementation:* This is tricky because of pedal messages. The note is kept on by* either the key or the pedal. Keep 2 flags, key and ped. Key is* turned off when a key is released, ped goes off and on with pedal.* Note ends when (1) both key and ped are FALSE, (2) key is* pressed (this event will also start another note).****************************************************************************/private long getdur(i, last, ped, now)int i;note_type last;int ped;long now;{ int key = TRUE; /* flag that says if note is on */ long start = now; int chan = event_buff[i].n[0] & MIDI_CHN_MASK; int pitch = event_buff[i].n[1]; note_type note = &(event_buff[i+1]); int noteon; /* TRUE if a noteon message received on chan */ int keyon; /* TRUE if noteon message had non-zero velocity */ /* search from the next event (i+1) to the end of the buffer: */ for (; note < last; note++) { if (istime(note)) { now = note->when; } else { noteon = keyon = FALSE; if ((note->n[0] & MIDI_CHN_MASK) == chan) { noteon = ((note->n[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) && (note->n[1] == pitch); keyon = noteon && (note->n[2] != 0); if ((noteon && (note->n[2] == 0)) || (((note->n[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) && (note->n[1] == pitch))) key = FALSE; if (((note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) && note->n[1] == SUSTAIN && note->n[2] == 127) ped = TRUE; if (((note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) && note->n[1] == SUSTAIN && note->n[2] == 0) ped = FALSE; if ((!key && !ped) || keyon) return(now - start); } } } return(last->when - start);}/***************************************************************************** getnext* Inputs:* int i: the index of the current note* note_type last: pointer to last valid data* long now: the current time* Outputs:* returns long: the time of the next note, program, or control change* (returns time of last event if nothing else is found)****************************************************************************/private long getnext(i, last, now)int i; /* the index of the current note */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -