2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2007 Reuben Thomas
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.
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.
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.
31 /*------------------------------------------------------------------------------
32 ** Macros to handle big/little endian issues, and other magic numbers.
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
42 /*------------------------------------------------------------------------------
43 ** Private static functions.
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
) ;
50 /*------------------------------------------------------------------------------
55 wve_open (SF_PRIVATE
*psf
)
59 return SFE_WVE_NO_PIPE
;
61 if (psf
->file
.mode
== SFM_READ
|| (psf
->file
.mode
== SFM_RDWR
&& psf
->filelength
> 0))
62 { if ((error
= wve_read_header (psf
)))
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
;
70 psf
->endian
= SF_ENDIAN_BIG
;
72 if ((error
= wve_write_header (psf
, SF_FALSE
)))
75 psf
->write_header
= wve_write_header
;
78 psf
->blockwidth
= psf
->bytewidth
* psf
->sf
.channels
;
80 psf
->container_close
= wve_close
;
82 error
= alaw_init (psf
) ;
87 /*------------------------------------------------------------------------------
91 wve_read_header (SF_PRIVATE
*psf
)
93 unsigned short version
, padding
, repeats
, trash
;
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
;
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
;
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
;
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
;
121 psf_binheader_readf (psf
, "E2", &version
) ;
123 psf_log_printf (psf
, "Psion Palmtop Alaw (.wve)\n"
124 " Sample Rate : 8000\n"
126 " Encoding : A-law\n") ;
128 if (version
!= PSION_VERSION
)
129 psf_log_printf (psf
, "Psion version %d should be %d\n", version
, PSION_VERSION
) ;
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
) ;
138 psf
->datalength
= datalength
;
140 psf_binheader_readf (psf
, "E22222", &padding
, &repeats
, &trash
, &trash
, &trash
) ;
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 ;
147 return SFE_NO_ERROR
;
148 } /* wve_read_header */
150 /*------------------------------------------------------------------------------
154 wve_write_header (SF_PRIVATE
*psf
, int calc_length
)
155 { sf_count_t current
;
158 current
= psf_ftell (psf
) ;
161 { psf
->filelength
= psf_get_filelen (psf
) ;
163 psf
->datalength
= psf
->filelength
- psf
->dataoffset
;
165 psf
->datalength
-= psf
->filelength
- psf
->dataend
;
167 psf
->sf
.frames
= psf
->datalength
/ (psf
->bytewidth
* psf
->sf
.channels
) ;
170 /* Reset the current header length to zero. */
171 psf
->header
[0] = 0 ;
173 psf_fseek (psf
, 0, SEEK_SET
) ;
176 datalen
= psf
->datalength
;
177 psf_binheader_writef (psf
, "Emmmm", ALAW_MARKER
, SOUN_MARKER
, DFIL_MARKER
, ESSN_MARKER
) ;
178 psf_binheader_writef (psf
, "E2422222", PSION_VERSION
, datalen
, 0, 0, 0, 0, 0) ;
179 psf_fwrite (psf
->header
, psf
->headindex
, 1, psf
) ;
181 if (psf
->sf
.channels
!= 1)
182 return SFE_CHANNEL_COUNT
;
187 psf
->dataoffset
= psf
->headindex
;
190 psf_fseek (psf
, current
, SEEK_SET
) ;
193 } /* wve_write_header */
195 /*------------------------------------------------------------------------------
199 wve_close (SF_PRIVATE
*psf
)
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
205 wve_write_header (psf
, SF_TRUE
) ;