2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
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.
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.
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.
30 /*------------------------------------------------------------------------------
31 ** Macros to handle big/little endian issues.
34 #define PVF1_MARKER (MAKE_MARKER ('P', 'V', 'F', '1'))
36 /*------------------------------------------------------------------------------
37 ** Private static functions.
40 static int pvf_close (SF_PRIVATE
*psf
) ;
42 static int pvf_write_header (SF_PRIVATE
*psf
, int calc_length
) ;
43 static int pvf_read_header (SF_PRIVATE
*psf
) ;
45 /*------------------------------------------------------------------------------
50 pvf_open (SF_PRIVATE
*psf
)
54 if (psf
->file
.mode
== SFM_READ
|| (psf
->file
.mode
== SFM_RDWR
&& psf
->filelength
> 0))
55 { if ((error
= pvf_read_header (psf
)))
59 subformat
= SF_CODEC (psf
->sf
.format
) ;
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
;
65 psf
->endian
= SF_ENDIAN_BIG
;
67 if (pvf_write_header (psf
, SF_FALSE
))
70 psf
->write_header
= pvf_write_header
;
73 psf
->container_close
= pvf_close
;
75 psf
->blockwidth
= psf
->bytewidth
* psf
->sf
.channels
;
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
) ;
90 /*------------------------------------------------------------------------------
94 pvf_close (SF_PRIVATE
* UNUSED (psf
))
100 pvf_write_header (SF_PRIVATE
*psf
, int UNUSED (calc_length
))
101 { sf_count_t current
;
103 if (psf
->pipeoffset
> 0)
106 current
= psf_ftell (psf
) ;
108 /* Reset the current header length to zero. */
109 psf
->header
[0] = 0 ;
112 if (psf
->is_pipe
== SF_FALSE
)
113 psf_fseek (psf
, 0, SEEK_SET
) ;
115 snprintf ((char*) psf
->header
, sizeof (psf
->header
), "PVF1\n%d %d %d\n",
116 psf
->sf
.channels
, psf
->sf
.samplerate
, psf
->bytewidth
* 8) ;
118 psf
->headindex
= strlen ((char*) psf
->header
) ;
120 /* Header construction complete so write it out. */
121 psf_fwrite (psf
->header
, psf
->headindex
, 1, psf
) ;
126 psf
->dataoffset
= psf
->headindex
;
129 psf_fseek (psf
, current
, SEEK_SET
) ;
132 } /* pvf_write_header */
135 pvf_read_header (SF_PRIVATE
*psf
)
137 int marker
, channels
, samplerate
, bitwidth
;
139 psf_binheader_readf (psf
, "pmj", 0, &marker
, 1) ;
140 psf_log_printf (psf
, "%M\n", marker
) ;
142 if (marker
!= PVF1_MARKER
)
143 return SFE_PVF_NO_PVF1
;
145 /* Grab characters up until a newline which is replaced by an EOS. */
146 psf_binheader_readf (psf
, "G", buffer
, sizeof (buffer
)) ;
148 if (sscanf (buffer
, "%d %d %d", &channels
, &samplerate
, &bitwidth
) != 3)
149 return SFE_PVF_BAD_HEADER
;
151 psf_log_printf (psf
, " Channels : %d\n Sample rate : %d\n Bit width : %d\n",
152 channels
, samplerate
, bitwidth
) ;
154 psf
->sf
.channels
= channels
;
155 psf
->sf
.samplerate
= samplerate
;
159 psf
->sf
.format
= SF_FORMAT_PVF
| SF_FORMAT_PCM_S8
;
164 psf
->sf
.format
= SF_FORMAT_PVF
| SF_FORMAT_PCM_16
;
168 psf
->sf
.format
= SF_FORMAT_PVF
| SF_FORMAT_PCM_32
;
173 return SFE_PVF_BAD_BITWIDTH
;
176 psf
->dataoffset
= psf_ftell (psf
) ;
177 psf_log_printf (psf
, " Data Offset : %D\n", psf
->dataoffset
) ;
179 psf
->endian
= SF_ENDIAN_BIG
;
181 psf
->datalength
= psf
->filelength
- psf
->dataoffset
;
182 psf
->blockwidth
= psf
->sf
.channels
* psf
->bytewidth
;
184 if (! psf
->sf
.frames
&& psf
->blockwidth
)
185 psf
->sf
.frames
= (psf
->filelength
- psf
->dataoffset
) / psf
->blockwidth
;
188 } /* pvf_read_header */