#include "aytool.h"
#include <errno.h>
#include <string.h>
static const char*fmt_mode(int fmt)
{
return (fmt == DATA_FORMAT_TXT || fmt == DATA_FORMAT_H)? "wt": "wb";
}
int check_files(const struct TOOL_PARAMS*tp)
{
int i, n2, n4;
for (i = n2 = n4 = 0; i < DATA_FORMATS_COUNT; ++i) {
if (tp->out_flags & (1 << i)) ++n2;
if (tp->nameo[i]) ++n4;
}
DEBUG("n2 = %d, n4 = %d", n2, n4);
if (!n2) {
ERROR("no output formats has been specified");
return 14;
}
if (!tp->namec && n2 != n4) {
ERROR("all output files has to be specified directly");
return 18;
}
if (tp->namec && n2 != n4) {
if (n4) INFO("some of output file names will be generated automatically");
else if (n2 != 1) INFO("all of output file names will be generated automatically");
else INFO("output file name will be generated automatically");
}
return 0;
}
static char* format_name(struct TOOL_CONTEXT*tc, const struct TOOL_PARAMS*tp, const char*name, int fmt, int is_out)
{
char*p = strrchr(name, '.');
int nc, n;
if (!p) nc = strlen(name);
else nc = p - name;
n = snprintf(tc->namebuf + tc->namebufofs, sizeof(tc->namebuf) - tc->namebufofs, "%.*s%s.%s", nc, name, is_out?"-out": "", io_flags_str[fmt]);
if (tc->namebufofs + n >= sizeof(tc->namebuf)) {
ERROR("name buffer overflow");
return NULL;
}
p = tc->namebuf + tc->namebufofs;
tc->namebufofs += n + 1;
return p;
}
int create_output(struct TOOL_CONTEXT*tc, const struct TOOL_PARAMS*tp, int com)
{
int i;
for (i = 0; i < DATA_FORMATS_COUNT; ++i) {
DEBUG("nameo[%d] = %s (%d), com = %d, fl = %d", i, tp->nameo[i], tp->nameo[i] != NULL, com, (tp->out_flags & (1 << i)));
if (((tp->nameo[i] != NULL) == com) && (tp->out_flags & (1 << i))) {
if (tp->nameo[i]) {
tc->outn[i] = tp->nameo[i];
} else {
tc->outn[i] = format_name(tc, tp, tp->namev[tc->name_ind], i, 0);
}
INFO("create output file %s...", tc->outn[i]);
tc->out[i] = fopen(tc->outn[i], fmt_mode(i));
if (!tc->out[i]) {
ERROR("failed to create output file %s: %s", tc->outn[i], strerror(errno));
return 21;
}
}
}
return 0;
}
int close_files(struct TOOL_CONTEXT*tc, const struct TOOL_PARAMS*tp, int com)
{
int i;
for (i = 0; i < DATA_FORMATS_COUNT; ++i) {
if ((tp->nameo[i] != NULL) == com && tc->out[i]) { fclose(tc->out[i]); tc->out[i] = NULL; }
}
return 0;
}
int process_name(struct TOOL_CONTEXT*tc, const struct TOOL_PARAMS*tp, int ind)
{
struct PROCESS_PARAMS pp = {0, tp->beat_rate, tp->base_rate, tp->step_rate, tp->chip_type, tp->chip_count};
int r = 0;
FILE*in;
switch (tp->chip_type) {
case CHIP_TYPE_AY8910:
pp.n_chan = tp->chip_count * 3;
break;
case CHIP_TYPE_TEXT:
pp.n_chan = MAX_CHIP_CHANS;
break;
}
tc->name_ind = ind;
midi_clear(&tc->mf);
OUTPUT("loading %s...", tp->namev[ind]);
in = fopen(tp->namev[ind], "rb");
if (!in) {
perror(tp->namev[ind]);
return 1;
}
r = midi_read(&tc->mf, in);
fclose(in);
if (r) return r;
INFO("midi: format: %d, div: %d, tracks: %d, events: %d", tc->mf.hdr.fmt, tc->mf.hdr.div, tc->mf.hdr.n_trk, tc->mf.trk[0].n_evt);
OUTPUT("expanding tones...");
r = midi_expand(&tc->mf, &tc->ei, tp->force_track - 1);
if (r) return r;
midi_free(&tc->mf);
INFO("time: %d, slices: %d, total instruments: %d, channels: %02X: %d->%d, notes: %d->%d, max: %d",
tc->ei.total_time, tc->ei.n_times,
tc->ei.n_instr, tc->ei.chan_mask, tc->ei.chan_range[0], tc->ei.chan_range[1], tc->ei.note_range[0], tc->ei.note_range[1], tc->ei.max_notes);
OUTPUT("processing...");
r = process_init(&tc->ps, &pp);
if (r) return r;
r = create_output(tc, tp, 0);
if (r) return r;
r = process_midi_start(&tc->ps, &tc->ei);
if (r) return r;
for (;;) {
r = process_midi_step(&tc->ps, &tc->ei);
if (r < 0) break;
switch (tp->chip_type) {
case CHIP_TYPE_AY8910:
produce_ay8910(&tc->ps, tc->out[DATA_FORMAT_BIN], tc->out[DATA_FORMAT_H], tc->out[DATA_FORMAT_TXT]);
break;
case CHIP_TYPE_TEXT:
produce_text(&tc->ps, tc->out[DATA_FORMAT_TXT]);
break;
}
if (r) { r = 0; break; }
}
INFO("duration: %d sec, %d steps", tc->ps.dur_sec, tc->ps.cur_step);
process_term(&tc->ps);
close_files(tc, tp, 0);
return r;
}
struct TOOL_CONTEXT tc;
int process_params(const struct TOOL_PARAMS*tp)
{
int r, j;
for (j = 0; j < tp->namec; ++j) {
r = process_name(&tc, tp, j);
if (r) goto fin;
}
fin: return r;
}
struct TOOL_PARAMS tps, *tp = &tps;
int main(int argc, char*argv[])
{
int r;
if (argc < 2) print_help(argv[0]);
tp->chip_type = CHIP_TYPE_AY8910;
tp->chip_count = 2;
tp->force_track = 0;
tp->base_rate = 1787500;
tp->step_rate = 50;
tp->beat_rate = 120;
r = parse_params(tp, argc, argv);
if (r) return r;
r = check_files(tp);
if (r) return r;
r = process_params(tp);
if (!r) {
OUTPUT("success");
} else {
OUTPUT("error %d", r);
}
return r;
}