source: mainline/uspace/lib/trackmod/protracker.c@ fd1b1ce

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fd1b1ce was 7e69e0e, checked in by Jiri Svoboda <jiri@…>, 11 years ago

Introducing trackmod and modplay.

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup trackmod
30 * @{
31 */
32/**
33 * @file Protracker module (.mod).
34 */
35
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <mem.h>
40
41#include "byteorder.h"
42#include "protracker.h"
43#include "trackmod.h"
44#include "types/protracker.h"
45
46/** Sample tag decoding table entry*/
47typedef struct {
48 /** Tag */
49 const char *tag;
50 /** Number of channels */
51 unsigned channels;
52} smptag_desc_t;
53
54/** Sample tag decoding table */
55static smptag_desc_t smp_tags[] = {
56 { .tag = "M.K.", .channels = 4 },
57 { .tag = "M!K!", .channels = 4 },
58 { .tag = "2CHN", .channels = 2 },
59 { .tag = "6CHN", .channels = 6 },
60 { .tag = "8CHN", .channels = 8 },
61 { .tag = "10CH", .channels = 10 },
62 { .tag = "12CH", .channels = 12 },
63 { .tag = "14CH", .channels = 14 },
64 { .tag = "16CH", .channels = 16 },
65 { .tag = "18CH", .channels = 18 },
66 { .tag = "20CH", .channels = 20 },
67 { .tag = "22CH", .channels = 22 },
68 { .tag = "24CH", .channels = 24 },
69 { .tag = "26CH", .channels = 26 },
70 { .tag = "28CH", .channels = 28 },
71 { .tag = "30CH", .channels = 30 },
72 { .tag = "32CH", .channels = 32 },
73};
74
75/** Decode sample tag.
76 *
77 * @param tag Tag
78 * @param channels Place to store number or channels.
79 * @return EOK on success, EINVAL if tag is not recognized.
80 */
81static int smp_tag_decode(uint8_t *tag, size_t *channels)
82{
83 size_t nentries = sizeof(smp_tags) / sizeof(smptag_desc_t);
84 size_t i;
85
86 for (i = 0; i < nentries; i++) {
87 if (memcmp(tag, smp_tags[i].tag, 4) == 0) {
88 *channels = smp_tags[i].channels;
89 return EOK;
90 }
91 }
92
93 return EINVAL;
94}
95
96/** Get number of patterns stored in file.
97 *
98 * @param olist Order list
99 * @return Number of patterns in file
100 */
101static size_t order_list_get_npatterns(protracker_order_list_t *olist)
102{
103 size_t i;
104 size_t max_pat;
105
106 max_pat = 0;
107 for (i = 0; i < protracker_olist_len; i++) {
108 if (olist->order_list[i] > max_pat)
109 max_pat = olist->order_list[i];
110 }
111
112 return 1 + max_pat;
113}
114
115/** Load protracker module.
116 *
117 * @param fname File name
118 * @param rmodule Place to store pointer to newly loaded module.
119 * @return EOK on success, ENONEM if out of memory, EIO on I/O error
120 * or if any error is found in the format of the file.
121 */
122int trackmod_protracker_load(char *fname, trackmod_module_t **rmodule)
123{
124 FILE *f = NULL;
125 trackmod_module_t *module = NULL;
126 protracker_31smp_t mod31;
127 protracker_15smp_t mod15;
128 protracker_order_list_t *order_list;
129 protracker_smp_t *sample;
130 size_t nread;
131 size_t samples;
132 size_t channels;
133 size_t patterns;
134 size_t cells;
135 size_t i, j;
136 int rc;
137
138 f = fopen(fname, "rb");
139 if (f == NULL) {
140 printf("Error opening file.\n");
141 rc = EIO;
142 goto error;
143 }
144
145 nread = fread(&mod31, 1, sizeof(protracker_31smp_t), f);
146 if (nread < sizeof(protracker_15smp_t)) {
147 printf("File too small.\n");
148 rc = EIO;
149 goto error;
150 }
151
152 if (nread == sizeof(protracker_31smp_t)) {
153 /* Could be 31-sample variant */
154 rc = smp_tag_decode(mod31.sample_tag, &channels);
155 if (rc != EOK) {
156 samples = 15;
157 channels = 4;
158 } else {
159 samples = 31;
160 }
161 } else {
162 samples = 15;
163 channels = 4;
164 }
165
166 if (samples == 15) {
167 memcpy(&mod15, &mod31, sizeof(protracker_15smp_t));
168
169 rc = fseek(f, sizeof(protracker_15smp_t), SEEK_SET);
170 if (rc != 0) {
171 printf("Error seeking.\n");
172 rc = EIO;
173 goto error;
174 }
175
176 order_list = &mod15.order_list;
177 sample = mod15.sample;
178 } else {
179 order_list = &mod31.order_list;
180 sample = mod31.sample;
181 }
182
183 patterns = order_list_get_npatterns(order_list);
184
185 module = trackmod_module_new();
186 if (module == NULL) {
187 printf("Out of memory.\n");
188 rc = ENOMEM;
189 goto error;
190 }
191
192 module->channels = channels;
193
194 module->samples = samples;
195 module->sample = calloc(sizeof(trackmod_sample_t), samples);
196 if (module->sample == NULL) {
197 printf("Out of memory.\n");
198 rc = ENOMEM;
199 goto error;
200 }
201
202 module->patterns = patterns;
203 module->pattern = calloc(sizeof(trackmod_pattern_t), patterns);
204 if (module->pattern == NULL) {
205 printf("Out of memory.\n");
206 rc = ENOMEM;
207 goto error;
208 }
209
210 /* Order list */
211 module->ord_list_len = order_list->order_list_len;
212 module->ord_list = calloc(sizeof(size_t), module->ord_list_len);
213 if (module->ord_list == NULL) {
214 printf("Out of memory.\n");
215 rc = ENOMEM;
216 goto error;
217 }
218
219 for (i = 0; i < order_list->order_list_len; i++) {
220 module->ord_list[i] = order_list->order_list[i];
221 }
222
223 /* Load patterns */
224
225 cells = channels * protracker_pattern_rows;
226
227 for (i = 0; i < patterns; i++) {
228 module->pattern[i].rows = protracker_pattern_rows;
229 module->pattern[i].channels = channels;
230 module->pattern[i].data = calloc(sizeof(uint32_t), cells);
231
232 nread = fread(module->pattern[i].data,
233 sizeof(uint32_t), cells, f);
234 if (nread != cells) {
235 printf("Error reading pattern.\n");
236 rc = EIO;
237 goto error;
238 }
239
240 /* Convert byte order */
241 for (j = 0; j < cells; j++) {
242 module->pattern[i].data[j] = uint32_t_be2host(
243 module->pattern[i].data[j]);
244 }
245 }
246
247 /* Load samples */
248 for (i = 0; i < samples; i++) {
249 module->sample[i].length =
250 uint16_t_be2host(sample[i].length) * 2;
251 module->sample[i].data = calloc(1, module->sample[i].length);
252 if (module->sample[i].data == NULL) {
253 printf("Error allocating sample.\n");
254 rc = ENOMEM;
255 goto error;
256 }
257
258 nread = fread(module->sample[i].data, 1, module->sample[i].length,
259 f);
260 if (nread != module->sample[i].length) {
261 printf("Error reading sample.\n");
262 rc = EIO;
263 goto error;
264 }
265
266 module->sample[i].def_vol = sample[i].def_vol;
267 module->sample[i].loop_start =
268 uint16_t_be2host(sample[i].loop_start) * 2;
269 module->sample[i].loop_len =
270 uint16_t_be2host(sample[i].loop_len) * 2;
271 if (module->sample[i].loop_len <= 2)
272 module->sample[i].loop_len = 0;
273 }
274
275 (void) fclose(f);
276
277 *rmodule = module;
278 return EOK;
279error:
280 if (module != NULL)
281 trackmod_module_destroy(module);
282 if (f != NULL)
283 (void) fclose(f);
284 return rc;
285}
286
287/** @}
288 */
Note: See TracBrowser for help on using the repository browser.