| /* Copyright (C) 2002 Jean-Marc Valin |
| File: wav_io.c |
| Routines to handle wav (RIFF) headers |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| - Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| - Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
| CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include "wav_io.h" |
| #include "opus_header.h" |
| |
| /* Adjust the stream->channel mapping to ensure the proper output order for |
| WAV files. */ |
| void adjust_wav_mapping(int mapping_family, int channels, unsigned char *stream_map) |
| { |
| unsigned char new_stream_map[8]; |
| int i; |
| /* If we aren't using one of the defined semantic channel maps, or we have |
| more channels than we know what to do with, use a default 1-1 mapping. */ |
| if(mapping_family != 1 || channels > 8) |
| return; |
| for(i = 0; i < channels; i++) |
| { |
| new_stream_map[wav_permute_matrix[channels-1][i]] = stream_map[i]; |
| } |
| memcpy(stream_map, new_stream_map, channels*sizeof(*stream_map)); |
| } |
| |
| static size_t fwrite_le32(opus_int32 i32, FILE *file) |
| { |
| unsigned char buf[4]; |
| buf[0]=(unsigned char)(i32&0xFF); |
| buf[1]=(unsigned char)(i32>>8&0xFF); |
| buf[2]=(unsigned char)(i32>>16&0xFF); |
| buf[3]=(unsigned char)(i32>>24&0xFF); |
| return fwrite(buf,4,1,file); |
| } |
| |
| static size_t fwrite_le16(int i16, FILE *file) |
| { |
| unsigned char buf[2]; |
| buf[0]=(unsigned char)(i16&0xFF); |
| buf[1]=(unsigned char)(i16>>8&0xFF); |
| return fwrite(buf,2,1,file); |
| } |
| |
| int write_wav_header(FILE *file, int rate, int mapping_family, int channels, int fp) |
| { |
| int ret; |
| int extensible; |
| |
| /* Multichannel files require a WAVEFORMATEXTENSIBLE header to declare the |
| proper channel meanings. */ |
| extensible = mapping_family == 1 && 3 <= channels && channels <= 8; |
| |
| /* >16 bit audio also requires WAVEFORMATEXTENSIBLE. */ |
| extensible |= fp; |
| |
| ret = fprintf (file, "RIFF") >= 0; |
| ret &= fwrite_le32 (0x7fffffff, file); |
| |
| ret &= fprintf (file, "WAVEfmt ") >= 0; |
| ret &= fwrite_le32 (extensible ? 40 : 16, file); |
| ret &= fwrite_le16 (extensible ? 0xfffe : (fp?3:1), file); |
| ret &= fwrite_le16 (channels, file); |
| ret &= fwrite_le32 (rate, file); |
| ret &= fwrite_le32 ((fp?4:2)*channels*rate, file); |
| ret &= fwrite_le16 ((fp?4:2)*channels, file); |
| ret &= fwrite_le16 (fp?32:16, file); |
| |
| if(extensible) |
| { |
| static const unsigned char ksdataformat_subtype_pcm[16]= |
| { |
| 0x01, 0x00, 0x00, 0x00, |
| 0x00, 0x00, |
| 0x10, 0x00, |
| 0x80, 0x00, |
| 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 |
| }; |
| static const unsigned char ksdataformat_subtype_float[16]= |
| { |
| 0x03, 0x00, 0x00, 0x00, |
| 0x00, 0x00, |
| 0x10, 0x00, |
| 0x80, 0x00, |
| 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 |
| }; |
| static const int wav_channel_masks[8] = |
| { |
| 1, /* 1.0 mono */ |
| 1|2, /* 2.0 stereo */ |
| 1|2|4, /* 3.0 channel ('wide') stereo */ |
| 1|2|16|32, /* 4.0 discrete quadrophonic */ |
| 1|2|4|16|32, /* 5.0 */ |
| 1|2|4|8|16|32, /* 5.1 */ |
| 1|2|4|8|256|512|1024, /* 6.1 */ |
| 1|2|4|8|16|32|512|1024, /* 7.1 */ |
| }; |
| ret &= fwrite_le16 (22, file); |
| ret &= fwrite_le16 (fp?32:16, file); |
| ret &= fwrite_le32 (wav_channel_masks[channels-1], file); |
| if (!fp) |
| { |
| ret &= fwrite (ksdataformat_subtype_pcm, 16, 1, file); |
| } else { |
| ret &= fwrite (ksdataformat_subtype_float, 16, 1, file); |
| } |
| } |
| |
| ret &= fprintf (file, "data") >= 0; |
| ret &= fwrite_le32 (0x7fffffff, file); |
| |
| return !ret ? -1 : extensible ? 40 : 16; |
| } |