2 * Copyright (c) 2011 Jan Vesely
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * @file PCM playback audio devices
35 #include <byteorder.h>
42 * Parse wav header data.
43 * @param[in] hdata Header data to parse.
44 * @param[out] data Pointer to audio data.
45 * @param[out] data_size Size of the data after the header.
46 * @param[out] channels Number of channels in stored audio format.
47 * @param[out] sampling_rate Sampling rate of the store data.
48 * @param[out] format Sample format.
49 * @param[out] error String representatoin of error, if any.
52 * Does sanity checks and endian conversion.
54 int wav_parse_header(const void *hdata
, const void **data
, size_t *data_size
,
55 unsigned *channels
, unsigned *sampling_rate
, pcm_sample_format_t
*format
,
64 const wave_header_t
*header
= hdata
;
65 if (str_lcmp(header
->chunk_id
, CHUNK_ID
, 4) != 0) {
67 *error
= "invalid chunk id";
71 if (str_lcmp(header
->format
, FORMAT_STR
, 4) != 0) {
73 *error
= "invalid format string";
77 if (str_lcmp(header
->subchunk1_id
, SUBCHUNK1_ID
, 4) != 0) {
79 *error
= "invalid subchunk1 id";
83 if (uint32_t_le2host(header
->subchunk1_size
) != PCM_SUBCHUNK1_SIZE
) {
84 //TODO subchunk 1 sizes other than 16 are allowed ( 18, 40)
85 //http://www-mmsp.ece.mcgill.ca/documents/AudioFormats/WAVE/WAVE.html
87 *error
= "invalid subchunk1 size";
91 if (uint16_t_le2host(header
->audio_format
) != FORMAT_LINEAR_PCM
) {
93 *error
= "unknown format";
97 if (str_lcmp(header
->subchunk2_id
, SUBCHUNK2_ID
, 4) != 0) {
98 //TODO basedd on subchunk1 size, we might be reading wrong
101 *error
= "invalid subchunk2 id";
106 //TODO data and data_size are incorrect in extended wav formats
109 *data
= header
->data
;
111 *data_size
= uint32_t_le2host(header
->subchunk2_size
);
114 *sampling_rate
= uint32_t_le2host(header
->sampling_rate
);
116 *channels
= uint16_t_le2host(header
->channels
);
118 const unsigned size
= uint16_t_le2host(header
->sample_size
);
120 case 8: *format
= PCM_SAMPLE_UINT8
; break;
121 case 16: *format
= PCM_SAMPLE_SINT16_LE
; break;
122 case 24: *format
= PCM_SAMPLE_SINT24_LE
; break;
123 case 32: *format
= PCM_SAMPLE_SINT32_LE
; break;
125 *error
= "Unknown format";
136 * Initialize wave fromat ehader structure.
137 * @param header Structure to initialize.
138 * @param format Desired PCM format
139 * @param size Size of the stored data.
141 * Initializes format specific elements and covnerts endian
143 void wav_init_header(wave_header_t
*header
, pcm_format_t format
, size_t size
)
146 #define COPY_STR(dst, src) memcpy(dst, src, str_size(src))
148 COPY_STR(&header
->chunk_id
, CHUNK_ID
);
149 COPY_STR(&header
->format
, FORMAT_STR
);
150 COPY_STR(&header
->subchunk1_id
, SUBCHUNK1_ID
);
151 header
->subchunk1_size
= host2uint16_t_le(PCM_SUBCHUNK1_SIZE
);
152 header
->audio_format
= host2uint16_t_le(FORMAT_LINEAR_PCM
);
154 COPY_STR(&header
->subchunk2_id
, SUBCHUNK2_ID
);
155 header
->subchunk2_size
= host2uint32_t_le(size
);
156 header
->sampling_rate
= host2uint32_t_le(format
.sampling_rate
);
157 header
->channels
= host2uint32_t_le(format
.channels
);
158 header
->sample_size
=
159 host2uint16_t_le(pcm_sample_format_size(format
.sample_format
) * 8);