📄 record.c
字号:
note_type last; /* pointer to last valid data */long now; /* the current time */{ i++; /* advance to next item */ for (; event_buff + i < last; i++) { note_type note = &(event_buff[i]); int cmd = note->n[0] & MIDI_CODE_MASK; if (istime(note)) { now = note->when; } else if (((cmd == MIDI_ON_NOTE) && (note->n[2] != 0)) /* note on */ || (cmd == MIDI_CH_PROGRAM) /* program change */ || ((cmd == MIDI_CTRL) && (note->n[1] != SUSTAIN) /* control change */ ) || (cmd == MIDI_TOUCH) || (cmd == MIDI_BEND)) { return(now); } } return(last->when);}/***************************************************************************** map_ctrl* Inputs:* int control: a midi control number* Outputs:* returns char: an adagio control change command letter, EOS if* control change is not one of PORTARATE, PORTASWITCH,* MODWHEEL, FOOT****************************************************************************/private char map_ctrl(control)int control;{ switch (control) {/* 'J' is no longer code for PORTARATE case PORTARATE: return 'J'; */ case PORTASWITCH: return 'K'; case MODWHEEL: return 'M'; case VOLUME: return 'X'; default: return EOS; }#ifdef LATTICE322 return EOS; /* make Lattice C type checker happy */#endif}/***************************************************************************** output* Inputs:* FILE *fp: an opened file pointer* note_type last: the last data in the buffer* boolean absflag: set to TRUE if first line of the adagio score should* include the absolute time* Effect: * write adagio file using data in event_buff* Implementation:* NOTE: put all program changes in rests* use N(ext) notation for all timing* output no more than one continuous parameter change per* clock tick for each continuous change parameter****************************************************************************/private void output(fp, last, absflag)FILE *fp;note_type last;boolean absflag;{ int i; /* loop counter */ int command; /* the current command */ int voice; /* the midi channel of the current event */ int last_velocity = -1; /* used to filter repeated Lnn attributes */ int last_voice = 0; /* the default adagio channel (1) */ int ped = FALSE; /* flag maintains state of pedal */ int how_many = last - event_buff; long now=0; /* the time of the next event */ if (fp == NULL) { gprintf(ERROR, "internal error: output called with NULL file.\n"); EXIT(1); } if (debug_rec) gprintf(GDEBUG,"hint: if file is not being closed, decrease MAXSPACE\n"); fprintf(fp, "!MSEC\n"); /* times will be in milliseconds */ /* set the initial absolute time, all other times are relative */ if (absflag) { now = event_buff[0].when; if (now < 0) { fprintf(fp, "* First event took place at Adagio time %d,\n", (int)now); fprintf(fp, "* but Adagio cannot represent negative times,\n"); fprintf(fp, "* so this entire score will be %d ms late\n", (int)-now); gprintf(TRANS, "First event took place at Adagio time %d!\n", (int)now); gprintf(TRANS, "All events times will be %d ms late\n", (int)-now); now = 0L; } fprintf(fp, "T%ld ", now); } for (i = 0; i < how_many; i++) { if (debug_rec) { gprintf(GDEBUG,"ev %d: %x %x %x (%ld)\n", i, event_buff[i].n[0], event_buff[i].n[1], event_buff[i].n[2], event_buff[i].when); } if (istime(event_buff+i)) { now = event_buff[i].when; if (debug_rec) gprintf(GDEBUG,"i = %d, now = %ld\n", i, now); } else { boolean needs_voice = TRUE; command = event_buff[i].n[0] & MIDI_CODE_MASK; voice = event_buff[i].n[0] & MIDI_CHN_MASK; if (command == MIDI_ON_NOTE && event_buff[i].n[2] != 0) { int velocity = event_buff[i].n[2]; write_pitch(fp, event_buff[i].n[1]); fprintf(fp, " U%ld", getdur(i, last, ped, now)); if (last_velocity != velocity) { fprintf(fp, " L%d", velocity); last_velocity = velocity; } } else if (command == MIDI_CH_PROGRAM) { fprintf(fp, "Z%d", event_buff[i].n[1] + 1); } else if (command == MIDI_CTRL && event_buff[i].n[1] == SUSTAIN) { ped = (event_buff[i].n[2] != 0); needs_voice = FALSE; } else if (command == MIDI_CTRL) { char c = map_ctrl(event_buff[i].n[1]); if (c != EOS) fprintf(fp, "%c%d", c, event_buff[i].n[2]); else fprintf(fp, "~%d(%d)", event_buff[i].n[1], event_buff[i].n[2]); } else if (command == MIDI_TOUCH) { fprintf(fp, "O%d", event_buff[i].n[1]); } else if (command == MIDI_BEND) { fprintf(fp, "Y%d", event_bend(&event_buff[i])); } else if (command == MIDI_ON_NOTE || command == MIDI_OFF_NOTE) { needs_voice = FALSE; /* ignore note-offs */ } else { gprintf(ERROR, "Command 0x%x ignored\n", command); needs_voice = FALSE; } if (needs_voice) { if (last_voice != voice) { fprintf(fp, " V%d", voice + 1); last_voice = voice; } fprintf(fp, " N%d", (int)(getnext(i, last, now) - now)); fprintf(fp, "\n"); } } }}/***************************************************************************** write_pitch* Inputs:* FILE *fp: an open file* int p: a pitch number* Effect: write out the pitch name for a given number****************************************************************************/void write_pitch(FILE *fp, int p){ static char *ptos[] = { "C", "CS", "D", "EF", "E", "F", "FS", "G", "GS", "A", "BF", "B" }; /* avoid negative numbers: adagio can't express lowest octave: */ while (p < 12) { if (!fixed_octave) { gprintf(ERROR, "%s%s%s", "A low note was transposed up an octave\n", "(Adagio cannot express the lowest MIDI octave).\n", "This message will appear only once.\n"); fixed_octave = TRUE; } p += 12; } fprintf(fp, "%s%d", ptos[p % 12], (p / 12) - 1);}/*********************************************************************** rec_final* Inputs:* boolean absflag: output absolute time of first note if TRUE* Effect:* Write recorded data to a file**********************************************************************/void rec_final(FILE *fp, boolean absflag){ next->when = gettime(); last = next; if (debug_rec) gprintf(GDEBUG,"max_pile_up = %d, ", max_pile_up); gprintf(TRANS,"%ld times and events recorded.\n", (long) (last - event_buff)); filter(last); output(fp, last, absflag); fclose(fp); FREE(event_buff); max_notes = -1;}/***************************************************************************** rec_init* Inputs:* char *file: pointer to file name from command line (if any)* boolean bender: TRUE if pitch bend should be enabled* Outputs:* return TRUE if initialization succeeds* Effect:* prepares module to record midi input****************************************************************************//* ENOUGH_ROOM says if we have room for 10000 events + 10000 timestamps = * 20000 note_struct's, then that's "enough room" for recording a sequence. * If more ram is available, it won't be used. If less is available, we'll * use as much as we can get, minus "SPACE_FOR_PLAY", which leaves a little * bit of spare ram in case Moxc or stdio need to allocate some space. * For DOS, we limit recording space to 64K. */#ifdef DOS#define ENOUGH_ROOM 64000L#else#define ENOUGH_ROOM (20000L * sizeof(union note_struct))#endifboolean rec_init(boolean bender){ size_t biggestChunk, spaceForRecord; debug_rec = cl_switch("debug"); byteorder(); pile_ups = 0; max_pile_up = 0; previous_time = (unsigned) -1L; /* this will force putting in initial timestamp */ fixed_octave = FALSE; if (max_notes == -1) { /* allocate space 1st time rec_init called */ biggestChunk = AVAILMEM; if (biggestChunk <= SPACE_FOR_PLAY) { /* not enough memory; give up */ return(FALSE); } else { spaceForRecord = MIN((biggestChunk - SPACE_FOR_PLAY), ENOUGH_ROOM); /* leave SPACE_FOR_PLAY contiguous bytes of memory */ } max_notes = spaceForRecord / sizeof(note_node); /* gprintf(GDEBUG,"max_notes = %d\n", max_notes);*/ event_buff = (note_type) MALLOC(spaceForRecord); if (event_buff == NULL) { /* should never happen */ gprintf(FATAL, "Implementation error (record.c): getting memory."); return FALSE; } } next = event_buff; last = event_buff + max_notes - 2; /* it is critical that last not point * to the very last storage loc */ midi_cont(bender); return((boolean)(max_notes > 10)); /* it would be silly to record with only room enough for 10 notes! */}/***************************************************************************** rec_event* Inputs:* long time: the current time* long data: midi data to record* Outputs:* returns FALSE if there is no more memory* Effect: reads and stores any input* Implementation:* time stamps and midi events share the same buffer of 4-byte events* save time at most once per call to rec_poll* save time only if it changes****************************************************************************/boolean rec_event(long *data, time_type time){ /* can't allow negative time because sign bit distinguishes * data from time: */ if (time < 0) time = 0; if (previous_time != time) { next++->when = previous_time = time; if (next >= last) goto overflow; } next->when = *data; next++->n[3] = MIDI_CMD_BIT; /* set tag bit */ if (next >= last) goto overflow; return TRUE;overflow: next = last; /* last doesn't really point to last storage */ gprintf(ERROR, "No more memory.\n"); return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -