1 /*
2 ** Copyright (C) 2002-2017 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2007 Reuben Thomas
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published by
7 ** the Free Software Foundation; either version 2.1 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU Lesser General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include "sfconfig.h"
21
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #include "sndfile.h"
28 #include "sfendian.h"
29 #include "common.h"
30
31 /*------------------------------------------------------------------------------
32 ** Macros to handle big/little endian issues, and other magic numbers.
33 */
34
35 #define ALAW_MARKER MAKE_MARKER ('A', 'L', 'a', 'w')
36 #define SOUN_MARKER MAKE_MARKER ('S', 'o', 'u', 'n')
37 #define DFIL_MARKER MAKE_MARKER ('d', 'F', 'i', 'l')
38 #define ESSN_MARKER MAKE_MARKER ('e', '*', '*', '\0')
39 #define PSION_VERSION ((unsigned short) 3856)
40 #define PSION_DATAOFFSET 0x20
41
42 /*------------------------------------------------------------------------------
43 ** Private static functions.
44 */
45
46 static int wve_read_header (SF_PRIVATE *psf) ;
47 static int wve_write_header (SF_PRIVATE *psf, int calc_length) ;
48 static int wve_close (SF_PRIVATE *psf) ;
49
50 /*------------------------------------------------------------------------------
51 ** Public function.
52 */
53
54 int
wve_open(SF_PRIVATE * psf)55 wve_open (SF_PRIVATE *psf)
56 { int error = 0 ;
57
58 if (psf->is_pipe)
59 return SFE_WVE_NO_PIPE ;
60
61 if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
62 { if ((error = wve_read_header (psf)))
63 return error ;
64 } ;
65
66 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
67 { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_WVE)
68 return SFE_BAD_OPEN_FORMAT ;
69
70 psf->endian = SF_ENDIAN_BIG ;
71
72 if ((error = wve_write_header (psf, SF_FALSE)))
73 return error ;
74
75 psf->write_header = wve_write_header ;
76 } ;
77
78 psf->blockwidth = psf->bytewidth * psf->sf.channels ;
79
80 psf->container_close = wve_close ;
81
82 error = alaw_init (psf) ;
83
84 return error ;
85 } /* wve_open */
86
87 /*------------------------------------------------------------------------------
88 */
89
90 static int
wve_read_header(SF_PRIVATE * psf)91 wve_read_header (SF_PRIVATE *psf)
92 { int marker ;
93 unsigned short version, padding, repeats, trash ;
94 unsigned datalength ;
95
96 /* Set position to start of file to begin reading header. */
97 psf_binheader_readf (psf, "pm", 0, &marker) ;
98 if (marker != ALAW_MARKER)
99 { psf_log_printf (psf, "Could not find '%M'\n", ALAW_MARKER) ;
100 return SFE_WVE_NOT_WVE ;
101 } ;
102
103 psf_binheader_readf (psf, "m", &marker) ;
104 if (marker != SOUN_MARKER)
105 { psf_log_printf (psf, "Could not find '%M'\n", SOUN_MARKER) ;
106 return SFE_WVE_NOT_WVE ;
107 } ;
108
109 psf_binheader_readf (psf, "m", &marker) ;
110 if (marker != DFIL_MARKER)
111 { psf_log_printf (psf, "Could not find '%M'\n", DFIL_MARKER) ;
112 return SFE_WVE_NOT_WVE ;
113 } ;
114
115 psf_binheader_readf (psf, "m", &marker) ;
116 if (marker != ESSN_MARKER)
117 { psf_log_printf (psf, "Could not find '%M'\n", ESSN_MARKER) ;
118 return SFE_WVE_NOT_WVE ;
119 } ;
120
121 psf_binheader_readf (psf, "E2", &version) ;
122
123 psf_log_printf (psf, "Psion Palmtop Alaw (.wve)\n"
124 " Sample Rate : 8000\n"
125 " Channels : 1\n"
126 " Encoding : A-law\n") ;
127
128 if (version != PSION_VERSION)
129 psf_log_printf (psf, "Psion version %d should be %d\n", version, PSION_VERSION) ;
130
131 psf_binheader_readf (psf, "E4", &datalength) ;
132 psf->dataoffset = PSION_DATAOFFSET ;
133 if (datalength != psf->filelength - psf->dataoffset)
134 { psf->datalength = psf->filelength - psf->dataoffset ;
135 psf_log_printf (psf, "Data length %d should be %D\n", datalength, psf->datalength) ;
136 }
137 else
138 psf->datalength = datalength ;
139
140 psf_binheader_readf (psf, "E22222", &padding, &repeats, &trash, &trash, &trash) ;
141
142 psf->sf.format = SF_FORMAT_WVE | SF_FORMAT_ALAW ;
143 psf->sf.samplerate = 8000 ;
144 psf->sf.frames = psf->datalength ;
145 psf->sf.channels = 1 ;
146
147 return SFE_NO_ERROR ;
148 } /* wve_read_header */
149
150 /*------------------------------------------------------------------------------
151 */
152
153 static int
wve_write_header(SF_PRIVATE * psf,int calc_length)154 wve_write_header (SF_PRIVATE *psf, int calc_length)
155 { sf_count_t current ;
156 unsigned datalen ;
157
158 current = psf_ftell (psf) ;
159
160 if (calc_length)
161 { psf->filelength = psf_get_filelen (psf) ;
162
163 psf->datalength = psf->filelength - psf->dataoffset ;
164 if (psf->dataend)
165 psf->datalength -= psf->filelength - psf->dataend ;
166
167 psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
168 } ;
169
170 /* Reset the current header length to zero. */
171 psf->header.ptr [0] = 0 ;
172 psf->header.indx = 0 ;
173 psf_fseek (psf, 0, SEEK_SET) ;
174
175 /* Write header. */
176 datalen = psf->datalength ;
177 psf_binheader_writef (psf, "Emmmm", BHWm (ALAW_MARKER), BHWm (SOUN_MARKER), BHWm (DFIL_MARKER), BHWm (ESSN_MARKER)) ;
178 psf_binheader_writef (psf, "E2422222", BHW2 (PSION_VERSION), BHW4 (datalen), BHW2 (0), BHW2 (0), BHW2 (0), BHW2 (0), BHW2 (0)) ;
179 psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
180
181 if (psf->sf.channels != 1)
182 return SFE_CHANNEL_COUNT ;
183
184 if (psf->error)
185 return psf->error ;
186
187 psf->dataoffset = psf->header.indx ;
188
189 if (current > 0)
190 psf_fseek (psf, current, SEEK_SET) ;
191
192 return psf->error ;
193 } /* wve_write_header */
194
195 /*------------------------------------------------------------------------------
196 */
197
198 static int
wve_close(SF_PRIVATE * psf)199 wve_close (SF_PRIVATE *psf)
200 {
201 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
202 { /* Now we know for certain the length of the file we can re-write
203 ** the header.
204 */
205 wve_write_header (psf, SF_TRUE) ;
206 } ;
207
208 return 0 ;
209 } /* wve_close */
210