Release 1.1
[alure.git] / src / codec_aiff.cpp
blobf7c1154a8791101291d1c7a5447d2b25e174fbe5
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
24 #include "config.h"
26 #include "main.h"
28 #include <string.h>
29 #include <assert.h>
31 #include <istream>
34 struct aiffStream : public alureStream {
35 private:
36 ALenum format;
37 int samplerate;
38 int blockAlign;
39 int sampleSize;
40 long dataStart;
41 long dataLen;
42 size_t remLen;
44 public:
45 static void Init() { }
46 static void Deinit() { }
48 virtual bool IsValid()
49 { return (dataStart > 0 && format != AL_NONE); }
51 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
53 *fmt = format;
54 *frequency = samplerate;
55 *blockalign = blockAlign;
56 return true;
59 virtual ALuint GetData(ALubyte *data, ALuint bytes)
61 std::streamsize rem = ((remLen >= bytes) ? bytes : remLen) / blockAlign;
62 fstream->read(reinterpret_cast<char*>(data), rem*blockAlign);
64 std::streamsize got = fstream->gcount();
65 got -= got%blockAlign;
66 remLen -= got;
68 if(LittleEndian)
70 if(sampleSize == 2)
72 for(std::streamsize i = 0;i < got;i+=2)
73 swap(data[i], data[i+1]);
75 else if(sampleSize == 4)
77 for(std::streamsize i = 0;i < got;i+=4)
79 swap(data[i+0], data[i+3]);
80 swap(data[i+1], data[i+2]);
85 return got;
88 virtual bool Rewind()
90 fstream->clear();
91 if(fstream->seekg(dataStart))
93 remLen = dataLen;
94 return true;
97 SetError("Seek failed");
98 return false;
101 aiffStream(std::istream *_fstream)
102 : alureStream(_fstream), format(0), dataStart(0)
104 ALubyte buffer[25];
105 int length;
107 if(!fstream->read(reinterpret_cast<char*>(buffer), 12) ||
108 memcmp(buffer, "FORM", 4) != 0 || memcmp(buffer+8, "AIFF", 4) != 0)
109 return;
111 while(!dataStart || format == AL_NONE)
113 char tag[4];
114 if(!fstream->read(tag, 4))
115 break;
117 /* read chunk length */
118 length = read_be32(fstream);
120 if(memcmp(tag, "COMM", 4) == 0 && length >= 18)
122 /* mono or stereo data */
123 int channels = read_be16(fstream);
125 /* number of sample frames */
126 fstream->ignore(4);
128 /* bits per sample */
129 sampleSize = read_be16(fstream) / 8;
131 /* sample frequency */
132 samplerate = read_be80extended(fstream);
134 /* block alignment */
135 blockAlign = channels * sampleSize;
137 format = GetSampleFormat(channels, sampleSize*8, false);
139 length -= 18;
141 else if(memcmp(tag, "SSND", 4) == 0)
143 dataStart = fstream->tellg();
144 dataStart += 8;
145 dataLen = remLen = length - 8;
148 fstream->seekg(length, std::ios_base::cur);
151 if(dataStart > 0 && format != AL_NONE)
152 fstream->seekg(dataStart);
155 virtual ~aiffStream()
158 // Priority = 9, prefer this decoder over external ones (but not the wave decoder)
159 static DecoderDecl<aiffStream,9> aiffStream_decoder;
160 Decoder &alure_init_aiff(void)
161 { return aiffStream_decoder; }