static int string_event_table_size = 0;
int default_channel_program[256];
static MidiEvent timesig[256];
+MS_Segment *ms_segments = NULL;
void init_delay_status_gs(void);
void init_chorus_status_gs(void);
if(counting_time == 2)
skip_this_event = 1;
break;
+
+ case ME_CUEPOINT:
+ if (counting_time == 2)
+ skip_this_event = 1;
+ break;
}
/* Recompute time in samples*/
}
}
+static int32 compute_smf_at_time(const int32);
+
+static void insert_cue_points(void)
+{
+ MS_Segment *sp;
+ int32 at, t;
+ uint8 a0, b0, a1, b1;
+
+ for (sp = ms_segments; sp != NULL; sp = sp->next) {
+ if (sp->prev == NULL && sp->begin != 0) {
+ at = compute_smf_at_time(0);
+ t = sp->begin * play_mode->rate * midi_time_ratio + 0.5;
+ a0 = t >> 24, b0 = t >> 16, a1 = t >> 8, b1 = t;
+ MIDIEVENT(at, ME_CUEPOINT, 0, a0, b0);
+ MIDIEVENT(at, ME_CUEPOINT, 1, a1, b1);
+ }
+ if (sp->next != NULL) {
+ at = compute_smf_at_time(sp->end * play_mode->rate);
+ t = (sp->next->begin - sp->end) * play_mode->rate \
+ * midi_time_ratio + 0.5;
+ a0 = t >> 24, b0 = t >> 16, a1 = t >> 8, b1 = t;
+ MIDIEVENT(at, ME_CUEPOINT, 0, a0, b0);
+ MIDIEVENT(at, ME_CUEPOINT, 1, a1, b1);
+ } else if (sp->end != -1) {
+ at = compute_smf_at_time(sp->end * play_mode->rate);
+ t = 0x7fffffff; /* stopper */
+ a0 = t >> 24, b0 = t >> 16, a1 = t >> 8, b1 = t;
+ MIDIEVENT(at, ME_CUEPOINT, 0, a0, b0);
+ MIDIEVENT(at, ME_CUEPOINT, 1, a1, b1);
+ }
+ }
+}
+
+static int32 compute_smf_at_time(const int32 sample)
+{
+ MidiEventList *e;
+ int32 st = 0, tempo = 500000, prev_time = 0;
+ int i;
+
+ for (i = 0, e = evlist; i < event_count; i++, e = e->next) {
+ st += (double) tempo * play_mode->rate / 1000000 \
+ / current_file_info->divisions \
+ * (e->event.time - prev_time) + 0.5;
+ if (st >= sample && e->event.type == ME_NOTE_STEP)
+ return e->event.time;
+ if (e->event.type == ME_TEMPO)
+ tempo = e->event.a * 65536 + e->event.b * 256 + e->event.channel;
+ prev_time = e->event.time;
+ }
+ return -1;
+}
+
+void free_ms_segments(void)
+{
+ MS_Segment *sp, *next;
+
+ for (sp = ms_segments; sp != NULL; sp = next)
+ next = sp->next, free(sp);
+ ms_segments = NULL;
+}
+
MidiEvent *read_midi_file(struct timidity_file *tf, int32 *count, int32 *sp,
char *fn)
{
grooming:
insert_note_steps();
+ insert_cue_points();
ev = groom_list(current_file_info->divisions, count, sp);
if(ev == NULL)
{
void free_readmidi(void)
{
reuse_mblock(&mempool);
+ free_ms_segments();
free_all_midi_file_info();
free_userdrum();
free_userinst();
TIM_OPT_EVIL,
TIM_OPT_FAST_PAN,
TIM_OPT_FAST_DECAY,
+ TIM_OPT_SEGMENT,
TIM_OPT_SPECTROGRAM,
TIM_OPT_KEYSIG,
TIM_OPT_HELP,
#else
static const char *optcommands =
#endif
- "4A:aB:b:C:c:D:d:E:eFfg:H:hI:i:jK:k:L:M:m:N:"
+ "4A:aB:b:C:c:D:d:E:eFfG:g:H:hI:i:jK:k:L:M:m:N:"
"O:o:P:p:Q:q:R:S:s:T:t:UV:vW:"
#ifdef __W32__
"w:"
#endif
- "x:Z:"; /* Only GJlnruXYyz are remain... */
+ "x:Z:"; /* Only JlnruXYyz are remain... */
#ifdef IA_WINSYN
const struct option longopts[] = {
#else
{ "fast-panning", optional_argument, NULL, TIM_OPT_FAST_PAN },
{ "no-fast-decay", no_argument, NULL, TIM_OPT_FAST_DECAY },
{ "fast-decay", optional_argument, NULL, TIM_OPT_FAST_DECAY },
+ { "segment", required_argument, NULL, TIM_OPT_SEGMENT },
{ "spectrogram", required_argument, NULL, TIM_OPT_SPECTROGRAM },
{ "force-keysig", required_argument, NULL, TIM_OPT_KEYSIG },
{ "help", optional_argument, NULL, TIM_OPT_HELP },
static inline int parse_opt_e(const char *);
static inline int parse_opt_F(const char *);
static inline int parse_opt_f(const char *);
+static inline int parse_opt_G(const char *);
+static int parse_segment(MS_Segment *, const char *);
+static int parse_time(FLOAT_T *, const char *);
static inline int parse_opt_g(const char *);
static inline int parse_opt_H(const char *);
__attribute__((noreturn))
static inline int parse_opt_fail(const char *);
static inline int set_value(int *, int, int, int, char *);
static inline int set_val_i32(int32 *, int32, int32, int32, char *);
-static int parse_val_float_t(FLOAT_T *param, const char *arg, FLOAT_T low, FLOAT_T high, const char *name);
-static inline int set_val_float_t(FLOAT_T *param, FLOAT_T i, FLOAT_T low, FLOAT_T high, const char *name);
+static int parse_val_float_t(FLOAT_T *, const char *, FLOAT_T, FLOAT_T,
+ const char *, int);
+static inline int set_val_float_t(FLOAT_T *, FLOAT_T, FLOAT_T, FLOAT_T,
+ const char *, int);
static inline int set_channel_flag(ChannelBitMask *, int32, char *);
static inline int y_or_n_p(const char *);
static inline int set_flag(int32 *, int32, const char *);
case 'f':
fast_decay = (fast_decay) ? 0 : 1;
break;
+ case 'G':
+ return parse_opt_G(optarg);
case 'g':
return parse_opt_g(optarg);
case 'H':
return parse_opt_F(arg);
case TIM_OPT_FAST_DECAY:
return parse_opt_f(arg);
+ case TIM_OPT_SEGMENT:
+ return parse_opt_G(arg);
case TIM_OPT_SPECTROGRAM:
return parse_opt_g(arg);
case TIM_OPT_KEYSIG:
/* scaleroom */
if (*p && *p != ',') {
if (parse_val_float_t(&freeverb_scaleroom, p, 0, 10,
- "Freeverb scaleroom"))
+ "Freeverb scaleroom", 1))
return 1;
}
if ((p = strchr(p, ',')) == NULL)
/* offsetroom */
if (*p && *p != ',') {
if (parse_val_float_t(&freeverb_offsetroom, p, 0, 10,
- "Freeverb offsetroom"))
+ "Freeverb offsetroom", 1))
return 1;
}
if ((p = strchr(p, ',')) == NULL)
return 0;
}
+static inline int parse_opt_G(const char *arg)
+{
+ /* play just sub-segment(s) */
+ MS_Segment *sp;
+ const char *p = arg;
+
+ ms_segments = (MS_Segment *) safe_malloc(sizeof(MS_Segment));
+ if (parse_segment(ms_segments, p)) {
+ free_ms_segments();
+ return 1;
+ }
+ ms_segments->prev = ms_segments->next = NULL;
+ for (sp = ms_segments; (p = strchr(p, ',')) != NULL; sp = sp->next) {
+ sp->next = (MS_Segment *) safe_malloc(sizeof(MS_Segment));
+ if (parse_segment(sp->next, ++p)) {
+ free_ms_segments();
+ return 1;
+ }
+ sp->next->prev = sp, sp->next->next = NULL;
+ }
+ for (sp = ms_segments; sp != NULL; sp = sp->next)
+ if (sp->prev != NULL && sp->begin <= sp->prev->end) {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Segments must be ordered");
+ free_ms_segments();
+ return 1;
+ } else if (sp->end != -1 && sp->begin >= sp->end) {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Segment time must be ordered");
+ free_ms_segments();
+ return 1;
+ }
+ return 0;
+}
+
+static int parse_segment(MS_Segment *seg, const char *p)
+{
+ const char *q;
+
+ if (*p == '-')
+ seg->begin = 0;
+ else if (parse_time(&seg->begin, p))
+ return 1;
+ p = ((q = strchr(p, '-')) == NULL) ? p + strlen(p) : q + 1;
+ if (*p == ',' || *p == '\0')
+ seg->end = -1;
+ else if (parse_time(&seg->end, p))
+ return 1;
+ return 0;
+}
+
+static int parse_time(FLOAT_T *param, const char *p)
+{
+ const char *p1, *p2;
+ int min;
+ FLOAT_T sec;
+
+ p1 = ((p1 = strchr(p, ':')) == NULL) ? p + strlen(p) : p1;
+ p2 = ((p2 = strchr(p, '-')) == NULL) ? p + strlen(p) : p2;
+ if (p1 < p2) {
+ if (set_value(&min, atoi(p), 0, 59, "Segment time (min part)"))
+ return 1;
+ if (parse_val_float_t(&sec, p1 + 1, 0, 59.999,
+ "Segment time (sec+frac part)", 3))
+ return 1;
+ *param = min * 60 + sec;
+ } else if (parse_val_float_t(param, p, 0, 3599.999, "Segment time", 3))
+ return 1;
+ return 0;
+}
+
static inline int parse_opt_g(const char *arg)
{
#ifdef SUPPORT_SOUNDSPEC
"Enable "
#endif
"fast decay mode (toggle)",
+" -G --segment=<begin>-<end>[,<begin2>-<end2>,...]",
+" Play just sub-segment(s), comma separated segments",
+" Each segment is dash separated of two time values of:",
+" <begin>-<end> - defaulted to 0-infinity",
+" Playing from <begin> to <end>",
+" Time format: [<minutes>:]<seconds>[.<milliseconds>]",
#ifdef SUPPORT_SOUNDSPEC
" -g sec --spectrogram=sec",
" Open Sound-Spectrogram Window",
{
if (i < low || i > high) {
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
- "%s must be between %ld and %ld", name, low, high);
+ "%s must be between %d and %d", name, low, high);
return 1;
}
*param = i;
}
static int parse_val_float_t(FLOAT_T *param,
- const char *arg, FLOAT_T low, FLOAT_T high, const char *name)
+ const char *arg, FLOAT_T low, FLOAT_T high, const char *name, int f)
{
FLOAT_T value;
char *errp;
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Invalid %s", name);
return 1;
}
- return set_val_float_t(param, value, low, high, name);
+ return set_val_float_t(param, value, low, high, name, f);
}
static inline int set_val_float_t(FLOAT_T *param,
- FLOAT_T i, FLOAT_T low, FLOAT_T high, const char *name)
+ FLOAT_T i, FLOAT_T low, FLOAT_T high, const char *name, int f)
{
if (i < low || i > high) {
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
- "%s must be between %.1f and %.1f", name, low, high);
+ "%s must be between %.*f and %.*f", name, f, low, f, high);
return 1;
}
*param = i;