1 /*
2 * Schism Tracker - a cross-platform Impulse Tracker clone
3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5 * copyright (c) 2009 Storlek & Mrs. Brisby
6 * copyright (c) 2010-2012 Storlek
7 * URL: http://schismtracker.org/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #define NEED_BYTESWAP
25 #include "headers.h"
26 #include "fmt.h"
27
28 #include "sndfile.h"
29 #include "song.h"
30 #include "it_defs.h"
31
32 /* --------------------------------------------------------------------- */
fmt_its_read_info(dmoz_file_t * file,const uint8_t * data,size_t length)33 int fmt_its_read_info(dmoz_file_t *file, const uint8_t *data, size_t length)
34 {
35 struct it_sample *its;
36
37 if (!(length > 80 && memcmp(data, "IMPS", 4) == 0))
38 return 0;
39
40 its = (struct it_sample *)data;
41 file->smp_length = bswapLE32(its->length);
42 file->smp_flags = 0;
43
44 if (its->flags & 2) {
45 file->smp_flags |= CHN_16BIT;
46 }
47 if (its->flags & 16) {
48 file->smp_flags |= CHN_LOOP;
49 if (its->flags & 64)
50 file->smp_flags |= CHN_PINGPONGLOOP;
51 }
52 if (its->flags & 32) {
53 file->smp_flags |= CHN_SUSTAINLOOP;
54 if (its->flags & 128)
55 file->smp_flags |= CHN_PINGPONGSUSTAIN;
56 }
57
58 if (its->dfp & 128) file->smp_flags |= CHN_PANNING;
59 if (its->flags & 4) file->smp_flags |= CHN_STEREO;
60
61 file->smp_defvol = its->vol;
62 file->smp_gblvol = its->gvl;
63 file->smp_vibrato_speed = its->vis;
64 file->smp_vibrato_depth = its->vid & 0x7f;
65 file->smp_vibrato_rate = its->vir;
66
67 file->smp_loop_start = bswapLE32(its->loopbegin);
68 file->smp_loop_end = bswapLE32(its->loopend);
69 file->smp_speed = bswapLE32(its->C5Speed);
70 file->smp_sustain_start = bswapLE32(its->susloopbegin);
71 file->smp_sustain_end = bswapLE32(its->susloopend);
72
73 file->smp_filename = strn_dup((const char *)its->filename, 12);
74 file->description = "Impulse Tracker Sample";
75 file->title = strn_dup((const char *)data + 20, 25);
76 file->type = TYPE_SAMPLE_EXTD;
77
78 return 1;
79 }
80
load_its_sample(const uint8_t * header,const uint8_t * data,size_t length,song_sample_t * smp)81 int load_its_sample(const uint8_t *header, const uint8_t *data, size_t length, song_sample_t *smp)
82 {
83 struct it_sample *its = (struct it_sample *)header;
84 uint32_t format;
85 uint32_t bp;
86
87 if (length < 80 || strncmp((const char *) header, "IMPS", 4) != 0)
88 return 0;
89 /* alright, let's get started */
90 smp->length = bswapLE32(its->length);
91 if ((its->flags & 1) == 0) {
92 // sample associated with header
93 return 0;
94 }
95
96 // endianness (always little)
97 format = SF_LE;
98 // channels
99 format |= (its->flags & 4) ? SF_SS : SF_M;
100 if (its->flags & 8) {
101 // compression algorithm
102 format |= (its->cvt & 4) ? SF_IT215 : SF_IT214;
103 } else {
104 // signedness (or delta?)
105 format |= (its->cvt & 4) ? SF_PCMD : (its->cvt & 1) ? SF_PCMS : SF_PCMU;
106 }
107 // bit width
108 format |= (its->flags & 2) ? SF_16 : SF_8;
109
110 smp->global_volume = its->gvl;
111 if (its->flags & 16) {
112 smp->flags |= CHN_LOOP;
113 if (its->flags & 64)
114 smp->flags |= CHN_PINGPONGLOOP;
115 }
116 if (its->flags & 32) {
117 smp->flags |= CHN_SUSTAINLOOP;
118 if (its->flags & 128)
119 smp->flags |= CHN_PINGPONGSUSTAIN;
120 }
121 smp->volume = its->vol * 4;
122 strncpy(smp->name, (const char *) its->name, 25);
123 smp->panning = (its->dfp & 127) * 4;
124 if (its->dfp & 128)
125 smp->flags |= CHN_PANNING;
126 smp->loop_start = bswapLE32(its->loopbegin);
127 smp->loop_end = bswapLE32(its->loopend);
128 smp->c5speed = bswapLE32(its->C5Speed);
129 smp->sustain_start = bswapLE32(its->susloopbegin);
130 smp->sustain_end = bswapLE32(its->susloopend);
131
132 int vibs[] = {VIB_SINE, VIB_RAMP_DOWN, VIB_SQUARE, VIB_RANDOM};
133 smp->vib_type = vibs[its->vit & 3];
134 smp->vib_rate = its->vir;
135 smp->vib_depth = its->vid;
136 smp->vib_speed = its->vis;
137
138 // sanity checks
139 // (I should probably have more of these in general)
140 if (smp->loop_start > smp->length) {
141 smp->loop_start = smp->length;
142 smp->flags &= ~(CHN_LOOP | CHN_PINGPONGLOOP);
143 }
144 if (smp->loop_end > smp->length) {
145 smp->loop_end = smp->length;
146 smp->flags &= ~(CHN_LOOP | CHN_PINGPONGLOOP);
147 }
148 if (smp->sustain_start > smp->length) {
149 smp->sustain_start = smp->length;
150 smp->flags &= ~(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
151 }
152 if (smp->sustain_end > smp->length) {
153 smp->sustain_end = smp->length;
154 smp->flags &= ~(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
155 }
156
157 bp = bswapLE32(its->samplepointer);
158
159 // dumb casts :P
160 return csf_read_sample((song_sample_t *) smp, format,
161 (const char *) (data + bp),
162 (uint32_t) (length - bp));
163 }
164
fmt_its_load_sample(const uint8_t * data,size_t length,song_sample_t * smp)165 int fmt_its_load_sample(const uint8_t *data, size_t length, song_sample_t *smp)
166 {
167 return load_its_sample(data, data, length, smp);
168 }
169
save_its_header(disko_t * fp,song_sample_t * smp)170 void save_its_header(disko_t *fp, song_sample_t *smp)
171 {
172 struct it_sample its = {};
173
174 its.id = bswapLE32(0x53504D49); // IMPS
175 strncpy((char *) its.filename, smp->filename, 12);
176 its.gvl = smp->global_volume;
177 if (smp->data && smp->length)
178 its.flags |= 1;
179 if (smp->flags & CHN_16BIT)
180 its.flags |= 2;
181 if (smp->flags & CHN_STEREO)
182 its.flags |= 4;
183 if (smp->flags & CHN_LOOP)
184 its.flags |= 16;
185 if (smp->flags & CHN_SUSTAINLOOP)
186 its.flags |= 32;
187 if (smp->flags & CHN_PINGPONGLOOP)
188 its.flags |= 64;
189 if (smp->flags & CHN_PINGPONGSUSTAIN)
190 its.flags |= 128;
191 its.vol = smp->volume / 4;
192 strncpy((char *) its.name, smp->name, 25);
193 its.name[25] = 0;
194 its.cvt = 1; // signed samples
195 its.dfp = smp->panning / 4;
196 if (smp->flags & CHN_PANNING)
197 its.dfp |= 0x80;
198 its.length = bswapLE32(smp->length);
199 its.loopbegin = bswapLE32(smp->loop_start);
200 its.loopend = bswapLE32(smp->loop_end);
201 its.C5Speed = bswapLE32(smp->c5speed);
202 its.susloopbegin = bswapLE32(smp->sustain_start);
203 its.susloopend = bswapLE32(smp->sustain_end);
204 //its.samplepointer = 42; - this will be filled in later
205 its.vis = smp->vib_speed;
206 its.vir = smp->vib_rate;
207 its.vid = smp->vib_depth;
208 switch (smp->vib_type) {
209 case VIB_RANDOM: its.vit = 3; break;
210 case VIB_SQUARE: its.vit = 2; break;
211 case VIB_RAMP_DOWN: its.vit = 1; break;
212 default:
213 case VIB_SINE: its.vit = 0; break;
214 }
215
216 disko_write(fp, &its, sizeof(its));
217 }
218
fmt_its_save_sample(disko_t * fp,song_sample_t * smp)219 int fmt_its_save_sample(disko_t *fp, song_sample_t *smp)
220 {
221 save_its_header(fp, smp);
222 csf_write_sample(fp, smp, SF_LE | SF_PCMS
223 | ((smp->flags & CHN_16BIT) ? SF_16 : SF_8)
224 | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M),
225 UINT32_MAX);
226
227 /* Write the sample pointer. In an ITS file, the sample data is right after the header,
228 so its position in the file will be the same as the size of the header. */
229 unsigned int tmp = bswapLE32(sizeof(struct it_sample));
230 disko_seek(fp, 0x48, SEEK_SET);
231 disko_write(fp, &tmp, 4);
232
233 return SAVE_SUCCESS;
234 }
235
236