1 // This file is part of Dust Racing 2D.
2 // Copyright (C) 2013 Jussi Lind <jussi.lind@iki.fi>
3 //
4 // Dust Racing 2D is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 // Dust Racing 2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Dust Racing 2D. If not, see <http://www.gnu.org/licenses/>.
15
16 #include "openaloggdata.hpp"
17
18 #include <AL/alc.h>
19
20 #include <cstdio>
21 #include <vector>
22 #include <stdexcept>
23
24 #include <vorbis/vorbisfile.h>
25
checkError()26 static bool checkError()
27 {
28 ALCenum error = alGetError();
29 return error == AL_NO_ERROR;
30 }
31
32 static const int BUFFER_SIZE = 32768; // 32 KB buffers
33
34 // This routine is originally from
35 // http://www.gamedev.net/page/resources/_/technical/game-programming/introduction-to-ogg-vorbis-r2031
loadOgg(const char * fileName,std::vector<char> & buffer,ALenum & format,ALsizei & freq)36 static void loadOgg(const char * fileName, std::vector<char> & buffer, ALenum & format, ALsizei & freq)
37 {
38 int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
39 int bitStream;
40 long bytes;
41 char array[BUFFER_SIZE]; // Local fixed size array
42 FILE * f;
43
44 // Open for binary reading
45 f = std::fopen(fileName, "rb");
46
47 vorbis_info * pInfo;
48 OggVorbis_File oggFile;
49 ov_open(f, &oggFile, NULL, 0);
50
51 // Get some information about the OGG file
52 pInfo = ov_info(&oggFile, -1);
53
54 // Check the number of channels... always use 16-bit samples
55 if (pInfo->channels == 1)
56 {
57 format = AL_FORMAT_MONO16;
58 }
59 else
60 {
61 format = AL_FORMAT_STEREO16;
62 }
63
64 freq = pInfo->rate;
65
66 do
67 {
68 // Read up to a buffer's worth of decoded sound data
69 bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
70
71 // Append to end of buffer
72 buffer.insert(buffer.end(), array, array + bytes);
73
74 } while (bytes > 0);
75
76 ov_clear(&oggFile);
77 }
78
OpenALOggData(const std::string & path)79 OpenALOggData::OpenALOggData(const std::string & path)
80 : m_freq(0)
81 , m_buffer(0)
82 {
83 load(path);
84 }
85
load(const std::string & path)86 void OpenALOggData::load(const std::string & path)
87 {
88 Data::load(path);
89
90 alGetError();
91
92 if (!m_buffer)
93 {
94 alGenBuffers(1, &m_buffer);
95 }
96
97 std::vector<char> oggBuffer;
98 loadOgg(path.c_str(), oggBuffer, m_format, m_freq);
99
100 alBufferData(m_buffer, m_format, &oggBuffer[0], static_cast<ALsizei>(oggBuffer.size()), m_freq);
101
102 if (!checkError())
103 {
104 throw std::runtime_error("Failed to set buffer data of '" + path + "'");
105 }
106 }
107
buffer() const108 ALuint OpenALOggData::buffer() const
109 {
110 return m_buffer;
111 }
112
~OpenALOggData()113 OpenALOggData::~OpenALOggData()
114 {
115 alDeleteBuffers(1, &m_buffer);
116 }
117