2 This file is part of xm2btn.
4 xm2btn is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 xm2btn is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with xm2btn. If not, see <http://www.gnu.org/licenses/>.
33 /* Converts the given slot to target types. */
34 static void slot_to_targets(const struct xm_pattern_slot
*slot
, int *target_types
)
37 int lane_indexes
[2]; /* Max 2 targets */
39 for (i
= 0; i
< 5; ++i
)
43 /* Note determines which lanes are used */
44 switch ((slot
->note
- 1) % 12) {
45 case 0: /* C = left */
46 lane_indexes
[lane_count
++] = 0;
48 case 1: /* C# = left + B */
49 lane_indexes
[lane_count
++] = 0;
50 lane_indexes
[lane_count
++] = 3;
52 case 2: /* D = right */
53 lane_indexes
[lane_count
++] = 1;
55 case 3: /* D# = left + A */
56 lane_indexes
[lane_count
++] = 0;
57 lane_indexes
[lane_count
++] = 4;
59 case 4: /* E = select */
60 lane_indexes
[lane_count
++] = 2;
63 lane_indexes
[lane_count
++] = 3;
65 case 6: /* F# = right + B */
66 lane_indexes
[lane_count
++] = 1;
67 lane_indexes
[lane_count
++] = 3;
70 lane_indexes
[lane_count
++] = 4;
72 case 8: /* G# = right + A */
73 lane_indexes
[lane_count
++] = 1;
74 lane_indexes
[lane_count
++] = 4;
76 case 9: /* A, A#, B = B + A */
79 lane_indexes
[lane_count
++] = 3;
80 lane_indexes
[lane_count
++] = 4;
83 /* Effect parameter determines target type */
84 assert(lane_count
<= 2);
85 for (i
= 0; i
< lane_count
; ++i
) {
86 int type
= (i
== 0) ? (slot
->effect_param
>> 4) : (slot
->effect_param
& 0xF);
87 target_types
[lane_indexes
[i
]] = type
;
91 static int first_target_lane(int lanes_specifier
)
93 switch (lanes_specifier
) {
108 static int second_target_lane(int lanes_specifier
)
110 switch (lanes_specifier
) {
120 static int targets_to_lanes_specifier(const int *target_types
)
124 for (i
= 0; i
< 5; ++i
) {
125 if (target_types
[i
] != -1)
157 struct output_stream
{
164 static void output_stream_init(struct output_stream
*stream
, FILE *fp
)
167 stream
->bit_index
= 0;
172 static void output_stream_put_helper(struct output_stream
*stream
)
174 if (stream
->column
== 16) {
176 fprintf(stream
->fp
, "\n");
180 fprintf(stream
->fp
, "%s$%.2X", (stream
->column
== 0) ? ".db " : ",", stream
->bits
);
185 static void output_stream_put_bits(struct output_stream
*stream
, int n
, int v
)
188 /* fprintf(stdout, "output %d %X\n", n, v); */
189 for (i
= n
-1; i
>= 0; --i
) {
190 if (!(stream
->bit_index
& 7) && stream
->bit_index
)
191 output_stream_put_helper(stream
);
192 stream
->bits
|= ((v
& (1 << i
)) >> i
) << (7 - (stream
->bit_index
& 7));
197 static void output_stream_flush(struct output_stream
*stream
)
199 if (!stream
->bit_index
)
201 output_stream_put_helper(stream
);
204 static void output_delay(struct output_stream
*stream
, int delay
, int *pospos
)
210 static int factors
[8] = { 1, 2, 4, 8, 12, 16, 24, 32 };
212 for (i
= 7; i
>= 0; --i
) {
213 int rem
= delay
% factors
[i
];
225 for (i
= pos
-1; i
> 0; --i
) {
226 output_stream_put_bits(stream
, 3, buf
[i
]);
227 /* Insert empty row (effectively extending the delay) */
228 output_stream_put_bits(stream
, 4, 0);
231 output_stream_put_bits(stream
, 3, buf
[0]);
235 static void log_target(int difficulty
, int order_pos
, int row
, int lane
, int type
,
238 ++target_counts
[difficulty
*5*8 + lane
*8 + type
];
247 static void init_marker(struct marker_info
*m
, int data_offset
, int order_pos
, int pattern_row
)
249 m
->data_offset
= data_offset
;
250 m
->order_pos
= order_pos
;
251 m
->pattern_row
= pattern_row
;
255 Converts the given \a xm to D-Pad hero button data; writes the 6502
256 assembly language representation of the song to \a out.
258 void convert_xm_to_btn(const struct xm
*xm
, const struct xm2btn_options
*options
, FILE *out
)
261 static const int channel_base
= 5; /* Our data begins in channel 5 */
262 static const char *difficulty_strings
[3] = { "easy", "normal", "hard" };
263 for (difficulty
= 0; difficulty
< 3; ++difficulty
) {
266 int marker_count
= 0;
267 struct marker_info markers
[64];
268 enum MarkState mark_state
= NoMark
;
270 /* The 1st pass counts the number of items */
271 /* The 2nd pass outputs the data */
272 for (pass
= 0; pass
< 2; ++pass
) {
275 struct output_stream stream
;
276 output_stream_init(&stream
, (pass
== 1) ? out
: 0);
277 /* 1st marker is always beginning of song */
278 init_marker(&markers
[marker_count
++], 0, 0, 0);
280 /* Output the header */
282 static const int chunk_count
= 40; /* Total number of progress chunks (UI-dependent) */
284 items_per_chunk
= length
/ chunk_count
;
285 assert(items_per_chunk
< 256);
286 fprintf(out
, "%s%s:\n", options
->label_prefix
, difficulty_strings
[difficulty
]);
287 fprintf(out
, ".db $%.2X,$%.2X\n", xm
->header
.default_tempo
+ 1, items_per_chunk
);
288 fprintf(out
, ".dw %s%s_data\n", options
->label_prefix
, difficulty_strings
[difficulty
]);
292 for (i
= 0; i
< marker_count
; ++i
) {
293 const struct marker_info
*m
= &markers
[i
];
294 fprintf(out
, ".dw $%.4X : .db $%.2X,$%.2X\n",
295 m
->data_offset
, m
->order_pos
, m
->pattern_row
);
299 fprintf(out
, "%s%s_data:\n", options
->label_prefix
, difficulty_strings
[difficulty
]);
302 for (order_pos
= 0; order_pos
< xm
->header
.song_length
; ++order_pos
) {
306 const struct xm_pattern
*pattern
= &xm
->patterns
[xm
->header
.pattern_order_table
[order_pos
]];
307 for (row
= 0; row
< pattern
->row_count
; ++row
) {
310 const struct xm_pattern_slot
*row_data
= &pattern
->data
[row
* xm
->header
.channel_count
];
311 const struct xm_pattern_slot
*slot
= row_data
+ channel_base
+ difficulty
;
312 if (slot
->effect_type
== 7) {
313 /* Marker begin/end */
314 if (mark_state
== NoMark
) {
315 mark_state
= BeginMark
;
317 if (mark_state
!= Marking
) {
318 fprintf(stderr
, "bad marker at order %.2X, row %.2X, difficulty %d\n",
319 order_pos
, row
, difficulty
);
321 assert(mark_state
== Marking
);
322 mark_state
= EndMark
;
325 slot_to_targets(slot
, target_types
);
326 lanes
= targets_to_lanes_specifier(target_types
);
328 if (aux_delay
!= 0) {
329 /* "Flush" delay from previous pattern */
330 output_delay(&stream
, aux_delay
, &pos
);
335 if (mark_state
== BeginMark
) {
338 init_marker(&markers
[marker_count
++], stream
.bit_index
, order_pos
, /*row=*/0);
339 mark_state
= Marking
;
340 } else if (mark_state
== EndMark
) {
341 output_stream_put_bits(&stream
, 4, 0xE); /* end-marker */
344 output_stream_put_bits(&stream
, 4, 0); /* empty row */
347 output_delay(&stream
, delay
, &pos
);
349 if (mark_state
== BeginMark
) {
352 init_marker(&markers
[marker_count
++], stream
.bit_index
, order_pos
, row
);
353 mark_state
= Marking
;
354 } else if (mark_state
== EndMark
) {
355 output_stream_put_bits(&stream
, 4, 0xE); /* end-marker */
358 output_stream_put_bits(&stream
, 4, lanes
);
360 int l1
= first_target_lane(lanes
);
362 int t1
= target_types
[l1
];
363 output_stream_put_bits(&stream
, 1, t1
? 1 : 0); /* extended or normal */
365 output_stream_put_bits(&stream
, 3, t1
- 1);
366 if (pass
&& options
->log
) {
367 log_target(difficulty
, order_pos
, row
, l1
, t1
,
368 options
->target_counts
);
372 int l2
= second_target_lane(lanes
);
374 int t2
= target_types
[l2
];
375 output_stream_put_bits(&stream
, 1, t2
? 1 : 0); /* extended or normal */
377 output_stream_put_bits(&stream
, 3, t2
- 1);
378 if (pass
&& options
->log
) {
379 log_target(difficulty
, order_pos
, row
, l2
, t2
,
380 options
->target_counts
);
392 /* Terminate data: delay=0, end-of-data-marker=0x0F */
393 output_stream_put_bits(&stream
, 3, 0);
394 output_stream_put_bits(&stream
, 4, 0x0F);
395 output_stream_flush(&stream
);