xref: /third_party/libsnd/src/rx2.c (revision b815c7f3)
1/*
2** Copyright (C) 2001-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#include	"sfconfig.h"
20
21#include	<stdio.h>
22#include	<string.h>
23#include	<ctype.h>
24#include	<stdarg.h>
25
26#include	"sndfile.h"
27#include	"sfendian.h"
28#include	"common.h"
29
30#if (ENABLE_EXPERIMENTAL_CODE == 0)
31
32int
33rx2_open	(SF_PRIVATE *psf)
34{	if (psf)
35		return SFE_UNIMPLEMENTED ;
36	return 0 ;
37} /* rx2_open */
38
39#else
40
41/*------------------------------------------------------------------------------
42 * Macros to handle big/little endian issues.
43*/
44
45#define	CAT_MARKER	(MAKE_MARKER ('C', 'A', 'T', ' '))
46#define	GLOB_MARKER (MAKE_MARKER ('G', 'L', 'O', 'B'))
47
48#define	RECY_MARKER (MAKE_MARKER ('R', 'E', 'C', 'Y'))
49
50#define	SLCL_MARKER (MAKE_MARKER ('S', 'L', 'C', 'L'))
51#define	SLCE_MARKER (MAKE_MARKER ('S', 'L', 'C', 'E'))
52
53#define	DEVL_MARKER	(MAKE_MARKER ('D', 'E', 'V', 'L'))
54#define	TRSH_MARKER	(MAKE_MARKER ('T', 'R', 'S', 'H'))
55
56#define	EQ_MARKER	(MAKE_MARKER ('E', 'Q', ' ', ' '))
57#define	COMP_MARKER (MAKE_MARKER ('C', 'O', 'M', 'P'))
58
59#define	SINF_MARKER (MAKE_MARKER ('S', 'I', 'N', 'F'))
60#define	SDAT_MARKER (MAKE_MARKER ('S', 'D', 'A', 'T'))
61
62/*------------------------------------------------------------------------------
63 * Typedefs for file chunks.
64*/
65
66
67/*------------------------------------------------------------------------------
68 * Private static functions.
69*/
70static int	rx2_close	(SF_PRIVATE *psf) ;
71
72/*------------------------------------------------------------------------------
73** Public functions.
74*/
75
76int
77rx2_open	(SF_PRIVATE *psf)
78{	static const char *marker_type [4] =
79	{	"Original Enabled", "Enabled Hidden",
80		"Additional/PencilTool", "Disabled"
81		} ;
82
83	BUF_UNION	ubuf ;
84	int error, marker, length, glob_offset, slce_count, frames ;
85	int sdat_length = 0, slce_total = 0 ;
86	int n_channels ;
87
88
89	/* So far only doing read. */
90
91	psf_binheader_readf (psf, "Epm4", 0, &marker, &length) ;
92
93	if (marker != CAT_MARKER)
94	{	psf_log_printf (psf, "length : %d\n", length) ;
95		return -1000 ;
96		} ;
97
98	if (length != psf->filelength - 8)
99		psf_log_printf (psf, "%M : %d (should be %d)\n", marker, length, psf->filelength - 8) ;
100	else
101		psf_log_printf (psf, "%M : %d\n", marker, length) ;
102
103	/* 'REX2' marker */
104	psf_binheader_readf (psf, "m", &marker) ;
105	psf_log_printf (psf, "%M", marker) ;
106
107	/* 'HEAD' marker */
108	psf_binheader_readf (psf, "m", &marker) ;
109	psf_log_printf (psf, "%M\n", marker) ;
110
111	/* Grab 'GLOB' offset. */
112	psf_binheader_readf (psf, "E4", &glob_offset) ;
113	glob_offset += 0x14 ;	/* Add the current file offset. */
114
115	/* Jump to offset 0x30 */
116	psf_binheader_readf (psf, "p", 0x30) ;
117
118	/* Get name length */
119	length = 0 ;
120	psf_binheader_readf (psf, "1", &length) ;
121	if (length >= SIGNED_SIZEOF (ubuf.cbuf))
122	{	psf_log_printf (psf, "  Text : %d *** Error : Too sf_count_t!\n") ;
123		return -1001 ;
124		}
125
126	memset (ubuf.cbuf, 0, sizeof (ubuf.cbuf)) ;
127	psf_binheader_readf (psf, "b", ubuf.cbuf, length) ;
128	psf_log_printf (psf, " Text : \"%s\"\n", ubuf.cbuf) ;
129
130	/* Jump to GLOB offset position. */
131	if (glob_offset & 1)
132		glob_offset ++ ;
133
134	psf_binheader_readf (psf, "p", glob_offset) ;
135
136	slce_count = 0 ;
137	/* GLOB */
138	while (1)
139	{	psf_binheader_readf (psf, "m", &marker) ;
140
141		if (marker != SLCE_MARKER && slce_count > 0)
142		{	psf_log_printf (psf, "   SLCE count : %d\n", slce_count) ;
143			slce_count = 0 ;
144			}
145		switch (marker)
146		{	case GLOB_MARKER:
147					psf_binheader_readf (psf, "E4", &length) ;
148					psf_log_printf (psf, " %M : %d\n", marker, length) ;
149					psf_binheader_readf (psf, "j", length) ;
150					break ;
151
152			case RECY_MARKER:
153					psf_binheader_readf (psf, "E4", &length) ;
154					psf_log_printf (psf, " %M : %d\n", marker, length) ;
155					psf_binheader_readf (psf, "j", (length+1) & 0xFFFFFFFE) ; /* ?????? */
156					break ;
157
158			case CAT_MARKER:
159					psf_binheader_readf (psf, "E4", &length) ;
160					psf_log_printf (psf, " %M : %d\n", marker, length) ;
161					/*-psf_binheader_readf (psf, "j", length) ;-*/
162					break ;
163
164			case DEVL_MARKER:
165					psf_binheader_readf (psf, "mE4", &marker, &length) ;
166					psf_log_printf (psf, "  DEVL%M : %d\n", marker, length) ;
167					if (length & 1)
168						length ++ ;
169					psf_binheader_readf (psf, "j", length) ;
170					break ;
171
172			case EQ_MARKER:
173			case COMP_MARKER:
174					psf_binheader_readf (psf, "E4", &length) ;
175					psf_log_printf (psf, "   %M : %d\n", marker, length) ;
176					/* This is weird!!!! why make this (length - 1) */
177					if (length & 1)
178						length ++ ;
179					psf_binheader_readf (psf, "j", length) ;
180					break ;
181
182			case SLCL_MARKER:
183					psf_log_printf (psf, "  %M\n    (Offset, Next Offset, Type)\n", marker) ;
184					slce_count = 0 ;
185					break ;
186
187			case SLCE_MARKER:
188					{	int len [4], indx ;
189
190						psf_binheader_readf (psf, "E4444", &len [0], &len [1], &len [2], &len [3]) ;
191
192						indx = ((len [3] & 0x0000FFFF) >> 8) & 3 ;
193
194						if (len [2] == 1)
195						{	if (indx != 1)
196								indx = 3 ;	/* 2 cases, where next slice offset = 1 -> disabled & enabled/hidden */
197
198							psf_log_printf (psf, "   %M : (%6d, ?: 0x%X, %s)\n", marker, len [1], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ;
199							}
200						else
201						{	slce_total += len [2] ;
202
203							psf_log_printf (psf, "   %M : (%6d, SLCE_next_ofs:%d, ?: 0x%X, %s)\n", marker, len [1], len [2], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ;
204							} ;
205
206						slce_count ++ ;
207						} ;
208					break ;
209
210			case SINF_MARKER:
211					psf_binheader_readf (psf, "E4", &length) ;
212					psf_log_printf (psf, " %M : %d\n", marker, length) ;
213
214					psf_binheader_readf (psf, "E2", &n_channels) ;
215					n_channels = (n_channels & 0x0000FF00) >> 8 ;
216					psf_log_printf (psf, "  Channels    : %d\n", n_channels) ;
217
218					psf_binheader_readf (psf, "E44", &psf->sf.samplerate, &frames) ;
219					psf->sf.frames = frames ;
220					psf_log_printf (psf, "  Sample Rate : %d\n", psf->sf.samplerate) ;
221					psf_log_printf (psf, "  Frames      : %D\n", psf->sf.frames) ;
222
223					psf_binheader_readf (psf, "E4", &length) ;
224					psf_log_printf (psf, "  ??????????? : %d\n", length) ;
225
226					psf_binheader_readf (psf, "E4", &length) ;
227					psf_log_printf (psf, "  ??????????? : %d\n", length) ;
228					break ;
229
230			case SDAT_MARKER:
231					psf_binheader_readf (psf, "E4", &length) ;
232
233				sdat_length = length ;
234
235					/* Get the current offset. */
236					psf->dataoffset = psf_binheader_readf (psf, NULL) ;
237
238					if (psf->dataoffset + length != psf->filelength)
239						psf_log_printf (psf, " %M : %d (should be %d)\n", marker, length, psf->dataoffset + psf->filelength) ;
240					else
241						psf_log_printf (psf, " %M : %d\n", marker, length) ;
242					break ;
243
244			default :
245					psf_log_printf (psf, "Unknown marker : 0x%X %M", marker, marker) ;
246					return -1003 ;
247					break ;
248			} ;
249
250		/* SDAT always last marker in file. */
251		if (marker == SDAT_MARKER)
252			break ;
253		} ;
254
255	puts (psf->parselog.buf) ;
256	puts ("-----------------------------------") ;
257
258	printf ("SDAT length  : %d\n", sdat_length) ;
259	printf ("SLCE count   : %d\n", slce_count) ;
260
261	/* Hack for zero slice count. */
262	if (slce_count == 0 && slce_total == 1)
263		slce_total = frames ;
264
265	printf ("SLCE samples : %d\n", slce_total) ;
266
267	/* Two bytes per sample. */
268	printf ("Comp Ratio   : %f:1\n", (2.0 * slce_total * n_channels) / sdat_length) ;
269
270	puts (" ") ;
271
272	psf->parselog.buf [0] = 0 ;
273
274	/* OK, have the header although not too sure what it all means. */
275
276	psf->endian = SF_ENDIAN_BIG ;
277
278	psf->datalength = psf->filelength - psf->dataoffset ;
279
280 	if (psf_fseek (psf, psf->dataoffset, SEEK_SET))
281		return SFE_BAD_SEEK ;
282
283	psf->sf.format = (SF_FORMAT_REX2 | SF_FORMAT_DWVW_12) ;
284
285	psf->sf.channels	= 1 ;
286	psf->bytewidth		= 2 ;
287	psf->blockwidth		= psf->sf.channels * psf->bytewidth ;
288
289	if ((error = dwvw_init (psf, 16)))
290		return error ;
291
292	psf->container_close = rx2_close ;
293
294	if (! psf->sf.frames && psf->blockwidth)
295		psf->sf.frames = psf->datalength / psf->blockwidth ;
296
297	/* All done. */
298
299	return 0 ;
300} /* rx2_open */
301
302/*------------------------------------------------------------------------------
303*/
304
305static int
306rx2_close	(SF_PRIVATE *psf)
307{
308	if (psf->file.mode == SFM_WRITE)
309	{	/*  Now we know for certain the length of the file we can re-write
310		**	correct values for the FORM, 8SVX and BODY chunks.
311		*/
312
313		} ;
314
315	return 0 ;
316} /* rx2_close */
317
318#endif
319