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