Add tools/ and manual/, move sources to src/
[dpadhero2.git] / tools / xm2btn / xm.c
blobdf95baa69ebfc211031a5aa5d516bfccaee87a23
1 /*
2 This file is part of xm2nes.
4 xm2nes 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 xm2nes 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 xm2nes. If not, see <http://www.gnu.org/licenses/>.
18 #include "xm.h"
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #define read_byte(fp) (unsigned char)fgetc(fp)
25 /* Reads a short (little-endian) */
26 static unsigned short read_ushort(FILE *fp)
28 unsigned short result;
29 result = read_byte(fp); /* Low byte */
30 result |= read_byte(fp) << 8; /* High byte */
31 return result;
33 /* Reads an int (little-endian) */
34 static unsigned int read_uint(FILE *fp)
36 unsigned int result;
37 result = read_byte(fp); /* Low byte */
38 result |= read_byte(fp) << 8;
39 result |= read_byte(fp) << 16;
40 result |= read_byte(fp) << 24; /* High byte */
41 return result;
44 static int xm_read_header(FILE *fp, struct xm_header *out)
46 fread(&out->id_text, 1, 17, fp);
47 if (!strncmp(out->id_text, "Extended module: ", 17))
48 return XM_FORMAT_ERROR;
49 fread(&out->module_name, 1, 20, fp);
50 out->pad1a = read_byte(fp);
51 assert(out->pad1a == 0x1A);
52 fread(&out->tracker_name, 1, 20, fp);
53 out->version = read_ushort(fp);
54 if (out->version < 0x0104)
55 return XM_VERSION_ERROR;
56 out->header_size = read_uint(fp);
57 if (out->header_size != 0x0114)
58 return XM_HEADER_SIZE_ERROR;
59 out->song_length = read_ushort(fp);
60 out->restart_position = read_ushort(fp);
61 out->channel_count = read_ushort(fp);
62 out->pattern_count = read_ushort(fp);
63 out->instrument_count = read_ushort(fp);
64 out->flags = read_ushort(fp);
65 out->default_tempo = read_ushort(fp);
66 out->default_bpm = read_ushort(fp);
67 fread(&out->pattern_order_table, 1, 256, fp);
68 assert(ftell(fp) == 0x150);
69 assert(ftell(fp)-0x3C == out->header_size);
70 return XM_NO_ERROR;
73 static int xm_read_pattern(FILE *fp, int channel_count, struct xm_pattern *out)
75 unsigned int header_length;
76 unsigned char packing_type;
77 unsigned short row_count;
78 unsigned short packed_data_size;
79 long pos_before;
80 header_length = read_uint(fp);
81 assert(header_length == 9);
82 packing_type = read_byte(fp);
83 assert(packing_type == 0);
84 row_count = read_ushort(fp);
85 packed_data_size = read_ushort(fp);
86 pos_before = ftell(fp);
87 out->row_count = row_count;
88 out->data = (struct xm_pattern_slot*)malloc(channel_count * row_count * sizeof(struct xm_pattern_slot));
89 memset(out->data, 0, channel_count * row_count * sizeof(struct xm_pattern_slot));
90 if (packed_data_size != 0) {
91 /* unpack pattern data */
92 int row, column;
93 struct xm_pattern_slot *slot;
94 slot = out->data;
95 for (row = 0; row < row_count; ++row) {
96 for (column = 0; column < channel_count; ++column) {
97 unsigned char pattern_byte;
98 unsigned char note = 0, instrument = 0, volume = 0, effect_type = 0, effect_param = 0;
99 pattern_byte = read_byte(fp);
100 if (pattern_byte & 0x80) {
101 /* compressed */
102 if (pattern_byte & 0x01)
103 note = read_byte(fp);
104 if (pattern_byte & 0x02)
105 instrument = read_byte(fp);
106 if (pattern_byte & 0x04)
107 volume = read_byte(fp);
108 if (pattern_byte & 0x08)
109 effect_type = read_byte(fp);
110 if (pattern_byte & 0x10)
111 effect_param = read_byte(fp);
112 } else {
113 /* uncompressed */
114 note = pattern_byte;
115 instrument = read_byte(fp);
116 volume = read_byte(fp);
117 effect_type = read_byte(fp);
118 effect_param = read_byte(fp);
120 slot->note = note;
121 slot->instrument = instrument;
122 slot->volume = volume;
123 /* ### hackensack */
124 if ((effect_type == 0) && (effect_param != 0)) effect_type = 5; /* arpeggio */
125 slot->effect_type = effect_type;
126 slot->effect_param = effect_param;
127 ++slot;
130 assert(ftell(fp) == pos_before + packed_data_size);
132 return XM_NO_ERROR;
135 int xm_read(FILE *fp, struct xm *xm)
137 /* read header */
138 int ret = xm_read_header(fp, &xm->header);
139 if (ret)
140 return ret;
141 /* read patterns */
142 xm->patterns = (struct xm_pattern*)malloc(xm->header.pattern_count * sizeof(struct xm_pattern));
143 memset(xm->patterns, 0, xm->header.pattern_count * sizeof(struct xm_pattern));
145 int i;
146 for (i = 0; i < xm->header.pattern_count; ++i) {
147 ret = xm_read_pattern(fp, xm->header.channel_count, &xm->patterns[i]);
148 if (ret)
149 return ret;
152 return XM_NO_ERROR;
155 void xm_print_header(const struct xm_header *head, FILE *fp)
158 char tmp[21];
159 tmp[20] = '\0';
160 strncpy(tmp, head->module_name, 20);
161 fprintf(fp, "Module name: '%s'\n", tmp);
162 strncpy(tmp, head->tracker_name, 20);
163 fprintf(fp, "Tracker name: '%s'\n", tmp);
165 fprintf(fp, "Version: %.4X\n", head->version);
166 fprintf(fp, "Song length: %d\n", head->song_length);
167 fprintf(fp, "Restart position: %d\n", head->restart_position);
168 fprintf(fp, "Number of channels: %d\n", head->channel_count);
169 fprintf(fp, "Number of patterns: %d\n", head->pattern_count);
170 fprintf(fp, "Number of instruments: %d\n", head->instrument_count);
171 fprintf(fp, "Flags: %d\n", head->flags);
172 fprintf(fp, "Default tempo: %d\n", head->default_tempo);
173 fprintf(fp, "Default BPM: %d\n", head->default_bpm);
176 void xm_print_pattern(const struct xm *xm, int pindex, FILE *fp)
178 int row;
179 const struct xm_pattern *pat = &xm->patterns[pindex];
180 for (row = 0; row < pat->row_count; ++row) {
181 const struct xm_pattern_slot *slot = &pat->data[row * xm->header.channel_count];
182 fprintf(fp, "%.2x: %.2x %.2x %.2x %.2x %.2x\n",
183 row, slot->note, slot->instrument, slot->volume,
184 slot->effect_type, slot->effect_param);
188 void xm_destroy(struct xm *xm)
190 int i;
191 for (i = 0; i < xm->header.pattern_count; ++i)
192 free(xm->patterns[i].data);
193 free(xm->patterns);