xref: /third_party/libsnd/src/txw.c (revision b815c7f3)
1/*
2** Copyright (C) 2002-2012 Erik de Castro Lopo <erikd@mega-nerd.com>
3**
4** This program is free software; you can redistribute it and/or modify
5** it under the terms of the GNU Lesser General Public License as published by
6** the Free Software Foundation; either version 2.1 of the License, or
7** (at your option) any later version.
8**
9** This program 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 Lesser General Public License for more details.
13**
14** You should have received a copy of the GNU Lesser General Public License
15** along with this program; if not, write to the Free Software
16** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*/
18
19/*===========================================================================
20** Yamaha TX16 Sampler Files.
21**
22** This header parser was written using information from the SoX source code
23** and trial and error experimentation. The code here however is all original.
24*/
25
26#include	"sfconfig.h"
27
28#include	<stdio.h>
29#include	<fcntl.h>
30#include	<string.h>
31#include	<ctype.h>
32
33#include	"sndfile.h"
34#include	"sfendian.h"
35#include	"common.h"
36
37#if (ENABLE_EXPERIMENTAL_CODE == 0)
38
39int
40txw_open	(SF_PRIVATE *psf)
41{	if (psf)
42		return SFE_UNIMPLEMENTED ;
43	return 0 ;
44} /* txw_open */
45
46#else
47
48/*------------------------------------------------------------------------------
49** Markers.
50*/
51
52#define TXW_DATA_OFFSET		32
53
54#define	TXW_LOOPED			0x49
55#define	TXW_NO_LOOP			0xC9
56
57/*------------------------------------------------------------------------------
58** Private static functions.
59*/
60
61static int txw_read_header (SF_PRIVATE *psf) ;
62
63static sf_count_t txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
64static sf_count_t txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
65static sf_count_t txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
66static sf_count_t txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
67
68static sf_count_t txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
69
70/*------------------------------------------------------------------------------
71** Public functions.
72*/
73
74/*
75 * ftp://ftp.t0.or.at/pub/sound/tx16w/samples.yamaha
76 * ftp://ftp.t0.or.at/pub/sound/tx16w/faq/tx16w.tec
77 * http://www.t0.or.at/~mpakesch/tx16w/
78 *
79 * from tx16w.c sox 12.15: (7-Oct-98) (Mark Lakata and Leigh Smith)
80 *  char filetype[6] "LM8953"
81 *  nulls[10],
82 *  dummy_aeg[6]
83 *  format 0x49 = looped, 0xC9 = non-looped
84 *  sample_rate 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz
85 *  atc_length[3] if sample rate 0, [2]&0xfe = 6: 33kHz, 0x10:50, 0xf6: 16,
86 *					depending on [5] but to heck with it
87 *  rpt_length[3] (these are for looped samples, attack and loop lengths)
88 *  unused[2]
89 */
90
91typedef struct
92{	unsigned char	format, srate, sr2, sr3 ;
93	unsigned short	srhash ;
94	unsigned int	attacklen, repeatlen ;
95} TXW_HEADER ;
96
97#define	ERROR_666	666
98
99int
100txw_open	(SF_PRIVATE *psf)
101{	int error ;
102
103	if (psf->file.mode != SFM_READ)
104		return SFE_UNIMPLEMENTED ;
105
106	if ((error = txw_read_header (psf)))
107			return error ;
108
109 	if (psf_fseek (psf, psf->dataoffset, SEEK_SET) != psf->dataoffset)
110		return SFE_BAD_SEEK ;
111
112	psf->read_short		= txw_read_s ;
113	psf->read_int		= txw_read_i ;
114	psf->read_float		= txw_read_f ;
115	psf->read_double	= txw_read_d ;
116
117	psf->seek = txw_seek ;
118
119	return 0 ;
120} /* txw_open */
121
122/*------------------------------------------------------------------------------
123*/
124
125static int
126txw_read_header	(SF_PRIVATE *psf)
127{	BUF_UNION	ubuf ;
128	TXW_HEADER txwh ;
129	const char	*strptr ;
130
131	memset (&txwh, 0, sizeof (txwh)) ;
132	memset (ubuf.cbuf, 0, sizeof (ubuf.cbuf)) ;
133	psf_binheader_readf (psf, "pb", 0, ubuf.cbuf, 16) ;
134
135	if (memcmp (ubuf.cbuf, "LM8953\0\0\0\0\0\0\0\0\0\0", 16) != 0)
136		return ERROR_666 ;
137
138	psf_log_printf (psf, "Read only : Yamaha TX-16 Sampler (.txw)\nLM8953\n") ;
139
140	/* Jump 6 bytes (dummp_aeg), read format, read sample rate. */
141	psf_binheader_readf (psf, "j11", 6, &txwh.format, &txwh.srate) ;
142
143	/* 8 bytes (atc_length[3], rpt_length[3], unused[2]). */
144	psf_binheader_readf (psf, "e33j", &txwh.attacklen, &txwh.repeatlen, 2) ;
145	txwh.sr2 = (txwh.attacklen >> 16) & 0xFE ;
146	txwh.sr3 = (txwh.repeatlen >> 16) & 0xFE ;
147	txwh.attacklen &= 0x1FFFF ;
148	txwh.repeatlen &= 0x1FFFF ;
149
150	switch (txwh.format)
151	{	case TXW_LOOPED :
152				strptr = "looped" ;
153				break ;
154
155		case TXW_NO_LOOP :
156				strptr = "non-looped" ;
157				break ;
158
159		default :
160				psf_log_printf (psf, " Format      : 0x%02x => ?????\n", txwh.format) ;
161				return ERROR_666 ;
162		} ;
163
164	psf_log_printf (psf, " Format      : 0x%02X => %s\n", txwh.format, strptr) ;
165
166	strptr = NULL ;
167
168	switch (txwh.srate)
169	{	case 1 :
170				psf->sf.samplerate = 33333 ;
171				break ;
172
173		case 2 :
174				psf->sf.samplerate = 50000 ;
175				break ;
176
177		case 3 :
178				psf->sf.samplerate = 16667 ;
179				break ;
180
181		default :
182			/* This is ugly and braindead. */
183			txwh.srhash = ((txwh.sr2 & 0xFE) << 8) | (txwh.sr3 & 0xFE) ;
184			switch (txwh.srhash)
185			{	case ((0x6 << 8) | 0x52) :
186						psf->sf.samplerate = 33333 ;
187						break ;
188
189				case ((0x10 << 8) | 0x52) :
190						psf->sf.samplerate = 50000 ;
191						break ;
192
193				case ((0xF6 << 8) | 0x52) :
194						psf->sf.samplerate = 166667 ;
195						break ;
196
197				default :
198						strptr = " Sample Rate : Unknown : forcing to 33333\n" ;
199						psf->sf.samplerate = 33333 ;
200						break ;
201				} ;
202		} ;
203
204
205	if (strptr)
206		psf_log_printf (psf, strptr) ;
207	else if (txwh.srhash)
208		psf_log_printf (psf, " Sample Rate : %d (0x%X) => %d\n", txwh.srate, txwh.srhash, psf->sf.samplerate) ;
209	else
210		psf_log_printf (psf, " Sample Rate : %d => %d\n", txwh.srate, psf->sf.samplerate) ;
211
212	if (txwh.format == TXW_LOOPED)
213	{	psf_log_printf (psf, " Attack Len  : %d\n", txwh.attacklen) ;
214		psf_log_printf (psf, " Repeat Len  : %d\n", txwh.repeatlen) ;
215		} ;
216
217	psf->dataoffset = TXW_DATA_OFFSET ;
218	psf->datalength = psf->filelength - TXW_DATA_OFFSET ;
219	psf->sf.frames	= 2 * psf->datalength / 3 ;
220
221
222	if (psf->datalength % 3 == 1)
223		psf_log_printf (psf, "*** File seems to be truncated, %d extra bytes.\n",
224			(int) (psf->datalength % 3)) ;
225
226	if (txwh.attacklen + txwh.repeatlen > psf->sf.frames)
227		psf_log_printf (psf, "*** File has been truncated.\n") ;
228
229	psf->sf.format = SF_FORMAT_TXW | SF_FORMAT_PCM_16 ;
230	psf->sf.channels = 1 ;
231	psf->sf.sections = 1 ;
232	psf->sf.seekable = SF_TRUE ;
233
234	return 0 ;
235} /* txw_read_header */
236
237static sf_count_t
238txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
239{	BUF_UNION		ubuf ;
240	unsigned char	*ucptr ;
241	short			sample ;
242	int				k, bufferlen, readcount, count ;
243	sf_count_t		total = 0 ;
244
245	bufferlen = sizeof (ubuf.cbuf) / 3 ;
246	bufferlen -= (bufferlen & 1) ;
247	while (len > 0)
248	{	readcount = (len >= bufferlen) ? bufferlen : len ;
249		count = psf_fread (ubuf.cbuf, 3, readcount, psf) ;
250
251		ucptr = ubuf.ucbuf ;
252		for (k = 0 ; k < readcount ; k += 2)
253		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
254			ptr [total + k] = sample ;
255			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
256			ptr [total + k + 1] = sample ;
257			ucptr += 3 ;
258			} ;
259
260		total += count ;
261		len -= readcount ;
262		} ;
263
264	return total ;
265} /* txw_read_s */
266
267static sf_count_t
268txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
269{	BUF_UNION		ubuf ;
270	unsigned char	*ucptr ;
271	short			sample ;
272	int				k, bufferlen, readcount, count ;
273	sf_count_t		total = 0 ;
274
275	bufferlen = sizeof (ubuf.cbuf) / 3 ;
276	bufferlen -= (bufferlen & 1) ;
277	while (len > 0)
278	{	readcount = (len >= bufferlen) ? bufferlen : len ;
279		count = psf_fread (ubuf.cbuf, 3, readcount, psf) ;
280
281		ucptr = ubuf.ucbuf ;
282		for (k = 0 ; k < readcount ; k += 2)
283		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
284			ptr [total + k] = sample << 16 ;
285			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
286			ptr [total + k + 1] = sample << 16 ;
287			ucptr += 3 ;
288			} ;
289
290		total += count ;
291		len -= readcount ;
292		} ;
293
294	return total ;
295} /* txw_read_i */
296
297static sf_count_t
298txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
299{	BUF_UNION		ubuf ;
300	unsigned char	*ucptr ;
301	short			sample ;
302	int				k, bufferlen, readcount, count ;
303	sf_count_t		total = 0 ;
304	float			normfact ;
305
306	if (psf->norm_float == SF_TRUE)
307		normfact = 1.0 / 0x8000 ;
308	else
309		normfact = 1.0 / 0x10 ;
310
311	bufferlen = sizeof (ubuf.cbuf) / 3 ;
312	bufferlen -= (bufferlen & 1) ;
313	while (len > 0)
314	{	readcount = (len >= bufferlen) ? bufferlen : len ;
315		count = psf_fread (ubuf.cbuf, 3, readcount, psf) ;
316
317		ucptr = ubuf.ucbuf ;
318		for (k = 0 ; k < readcount ; k += 2)
319		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
320			ptr [total + k] = normfact * sample ;
321			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
322			ptr [total + k + 1] = normfact * sample ;
323			ucptr += 3 ;
324			} ;
325
326		total += count ;
327		len -= readcount ;
328		} ;
329
330	return total ;
331} /* txw_read_f */
332
333static sf_count_t
334txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
335{	BUF_UNION		ubuf ;
336	unsigned char	*ucptr ;
337	short			sample ;
338	int				k, bufferlen, readcount, count ;
339	sf_count_t		total = 0 ;
340	double			normfact ;
341
342	if (psf->norm_double == SF_TRUE)
343		normfact = 1.0 / 0x8000 ;
344	else
345		normfact = 1.0 / 0x10 ;
346
347	bufferlen = sizeof (ubuf.cbuf) / 3 ;
348	bufferlen -= (bufferlen & 1) ;
349	while (len > 0)
350	{	readcount = (len >= bufferlen) ? bufferlen : len ;
351		count = psf_fread (ubuf.cbuf, 3, readcount, psf) ;
352
353		ucptr = ubuf.ucbuf ;
354		for (k = 0 ; k < readcount ; k += 2)
355		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
356			ptr [total + k] = normfact * sample ;
357			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
358			ptr [total + k + 1] = normfact * sample ;
359			ucptr += 3 ;
360			} ;
361
362		total += count ;
363		len -= readcount ;
364		} ;
365
366	return total ;
367} /* txw_read_d */
368
369static sf_count_t
370txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
371{	if (psf && mode)
372		return offset ;
373
374	return 0 ;
375} /* txw_seek */
376
377#endif
378