1/* 2** Copyright (C) 2002-2016 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 <fcntl.h> 23#include <string.h> 24#include <ctype.h> 25 26#include "sndfile.h" 27#include "sfendian.h" 28#include "common.h" 29 30/*------------------------------------------------------------------------------ 31** Macros to handle big/little endian issues. 32*/ 33 34#define PVF1_MARKER (MAKE_MARKER ('P', 'V', 'F', '1')) 35 36/*------------------------------------------------------------------------------ 37** Private static functions. 38*/ 39 40static int pvf_close (SF_PRIVATE *psf) ; 41 42static int pvf_write_header (SF_PRIVATE *psf, int calc_length) ; 43static int pvf_read_header (SF_PRIVATE *psf) ; 44 45/*------------------------------------------------------------------------------ 46** Public function. 47*/ 48 49int 50pvf_open (SF_PRIVATE *psf) 51{ int subformat ; 52 int error = 0 ; 53 54 if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) 55 { if ((error = pvf_read_header (psf))) 56 return error ; 57 } ; 58 59 subformat = SF_CODEC (psf->sf.format) ; 60 61 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) 62 { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PVF) 63 return SFE_BAD_OPEN_FORMAT ; 64 65 psf->endian = SF_ENDIAN_BIG ; 66 67 if (pvf_write_header (psf, SF_FALSE)) 68 return psf->error ; 69 70 psf->write_header = pvf_write_header ; 71 } ; 72 73 psf->container_close = pvf_close ; 74 75 psf->blockwidth = psf->bytewidth * psf->sf.channels ; 76 77 switch (subformat) 78 { case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ 79 case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ 80 case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ 81 error = pcm_init (psf) ; 82 break ; 83 84 default : break ; 85 } ; 86 87 return error ; 88} /* pvf_open */ 89 90/*------------------------------------------------------------------------------ 91*/ 92 93static int 94pvf_close (SF_PRIVATE * UNUSED (psf)) 95{ 96 return 0 ; 97} /* pvf_close */ 98 99static int 100pvf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) 101{ sf_count_t current ; 102 103 if (psf->pipeoffset > 0) 104 return 0 ; 105 106 current = psf_ftell (psf) ; 107 108 /* Reset the current header length to zero. */ 109 psf->header.ptr [0] = 0 ; 110 psf->header.indx = 0 ; 111 112 if (psf->is_pipe == SF_FALSE) 113 psf_fseek (psf, 0, SEEK_SET) ; 114 115 snprintf ((char*) psf->header.ptr, psf->header.len, "PVF1\n%d %d %d\n", 116 psf->sf.channels, psf->sf.samplerate, psf->bytewidth * 8) ; 117 118 psf->header.indx = strlen ((char*) psf->header.ptr) ; 119 120 /* Header construction complete so write it out. */ 121 psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; 122 123 if (psf->error) 124 return psf->error ; 125 126 psf->dataoffset = psf->header.indx ; 127 128 if (current > 0) 129 psf_fseek (psf, current, SEEK_SET) ; 130 131 return psf->error ; 132} /* pvf_write_header */ 133 134static int 135pvf_read_header (SF_PRIVATE *psf) 136{ char buffer [32] ; 137 int marker, channels, samplerate, bitwidth ; 138 139 psf_binheader_readf (psf, "pmj", 0, &marker, 1) ; 140 psf_log_printf (psf, "%M\n", marker) ; 141 142 if (marker != PVF1_MARKER) 143 return SFE_PVF_NO_PVF1 ; 144 145 /* Grab characters up until a newline which is replaced by an EOS. */ 146 psf_binheader_readf (psf, "G", buffer, sizeof (buffer)) ; 147 148 if (sscanf (buffer, "%d %d %d", &channels, &samplerate, &bitwidth) != 3) 149 return SFE_PVF_BAD_HEADER ; 150 151 psf_log_printf (psf, " Channels : %d\n Sample rate : %d\n Bit width : %d\n", 152 channels, samplerate, bitwidth) ; 153 154 psf->sf.channels = channels ; 155 psf->sf.samplerate = samplerate ; 156 157 switch (bitwidth) 158 { case 8 : 159 psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_S8 ; 160 psf->bytewidth = 1 ; 161 break ; 162 163 case 16 : 164 psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_16 ; 165 psf->bytewidth = 2 ; 166 break ; 167 case 32 : 168 psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_32 ; 169 psf->bytewidth = 4 ; 170 break ; 171 172 default : 173 return SFE_PVF_BAD_BITWIDTH ; 174 } ; 175 176 psf->dataoffset = psf_ftell (psf) ; 177 psf_log_printf (psf, " Data Offset : %D\n", psf->dataoffset) ; 178 179 psf->endian = SF_ENDIAN_BIG ; 180 181 psf->datalength = psf->filelength - psf->dataoffset ; 182 psf->blockwidth = psf->sf.channels * psf->bytewidth ; 183 184 if (! psf->sf.frames && psf->blockwidth) 185 psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; 186 187 return 0 ; 188} /* pvf_read_header */ 189