Menu

[r163]: / tools / aytool / aytool.c  Maximize  Restore  History

Download this file

181 lines (164 with data), 4.8 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#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;
}
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.