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