OpenClonk
C4SoundLoaders.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 
17 #include "C4Include.h"
19 
20 #include "game/C4Application.h"
21 #include "platform/C4MusicFile.h"
22 
23 
24 using namespace C4SoundLoaders;
25 
27 
28 #if AUDIO_TK == AUDIO_TK_OPENAL && defined(__APPLE__)
29 namespace
30 {
31  static OSStatus AudioToolBoxReadCallback(void* context, SInt64 inPosition, UInt32 requestCount, void* buffer, UInt32* actualCount)
32  {
33  CFDataRef audio = (CFDataRef)context;
34  CFIndex audio_length = CFDataGetLength(audio);
35  int requestOffset = inPosition + requestCount;
36  int availableBytes = audio_length - inPosition;
37  if (requestOffset > audio_length) {
38  *actualCount = availableBytes;
39  } else {
40  *actualCount = requestCount;
41  }
42  CFRange range;
43  range.location = inPosition;
44  range.length = *actualCount;
45  CFDataGetBytes(audio, range, (UInt8*)buffer);
46  return noErr;
47  }
48  static SInt64 AudioToolBoxGetSizeProc(void* context)
49  {
50  return CFDataGetLength((CFDataRef)context);
51  }
52 }
53 
54 bool AppleSoundLoader::ReadInfo(SoundInfo* result, BYTE* data, size_t data_length, uint32_t)
55 {
56  CFDataRef data_container = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, data, data_length, kCFAllocatorNull);
57  AudioFileID sound_file;
58  OSStatus err = AudioFileOpenWithCallbacks((void*)data_container,
59  AudioToolBoxReadCallback,
60  nullptr,
61  AudioToolBoxGetSizeProc,
62  nullptr,
63  0,
64  &sound_file
65  );
66  if (err == noErr)
67  {
68  UInt32 property_size;
69 
70  uint64_t sound_data_size = 0;
71  property_size = sizeof(sound_data_size);
72  AudioFileGetProperty(sound_file, kAudioFilePropertyAudioDataByteCount, &property_size, &sound_data_size);
73 
74  result->sample_length = -1;
75  property_size = sizeof(result->sample_length);
76  AudioFileGetProperty(sound_file, kAudioFilePropertyEstimatedDuration, &property_size, &result->sample_length);
77 
78  UInt32 sound_data_size_32 = sound_data_size;
79  result->sound_data.resize(sound_data_size);
80  AudioFileReadBytes(sound_file, false, 0, &sound_data_size_32, &result->sound_data[0]);
81 
82  AudioStreamBasicDescription desc;
83  property_size = sizeof(desc);
84  AudioFileGetProperty(sound_file, kAudioFilePropertyDataFormat, &property_size, &desc);
85  result->sample_rate = desc.mSampleRate;
86 
87  switch (desc.mChannelsPerFrame)
88  {
89  case 1:
90  result->format = desc.mBitsPerChannel == 16 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8;
91  break;
92  case 2:
93  result->format = desc.mBitsPerChannel == 16 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8;
94  break;
95  default:
96  result->format = 0;
97  }
98  }
99  CFRelease(data_container);
100  return err == noErr;
101 }
102 
103 AppleSoundLoader AppleSoundLoader::singleton;
104 #endif
105 
106 #if AUDIO_TK == AUDIO_TK_OPENAL
107 size_t VorbisLoader::mem_read_func(void* ptr, size_t byte_size, size_t size_to_read, void* datasource)
108 {
109  size_t spaceToEOF;
110  size_t actualSizeToRead;
111  CompressedData* data = (CompressedData*)datasource;
112 
113  spaceToEOF = data->data_length - data->data_pos;
114  if (size_to_read*byte_size < spaceToEOF)
115  actualSizeToRead = size_to_read*byte_size;
116  else
117  actualSizeToRead = spaceToEOF;
118 
119  if (actualSizeToRead)
120  {
121  memcpy(ptr, (char*)data->data + data->data_pos, actualSizeToRead);
122  data->data_pos += actualSizeToRead;
123  }
124 
125  return actualSizeToRead;
126 }
127 
128 int VorbisLoader::mem_seek_func(void* datasource, ogg_int64_t offset, int whence)
129 {
130  CompressedData* data = (CompressedData*)datasource;
131 
132  switch (whence)
133  {
134  case SEEK_SET:
135  data->data_pos = static_cast<size_t>(offset) < data->data_length ? static_cast<size_t>(offset) : data->data_length;
136  break;
137  case SEEK_CUR:
138  data->data_pos += static_cast<size_t>(offset) < data->data_length - data->data_pos ? static_cast<size_t>(offset) : data->data_length - data->data_pos;
139  break;
140  case SEEK_END:
141  data->data_pos = data->data_length+1;
142  break;
143  }
144  return 0;
145 }
146 
147 int VorbisLoader::mem_close_func(void* datasource)
148 {
149  return 1;
150 }
151 
152 long VorbisLoader::mem_tell_func(void* datasource)
153 {
154  return ((CompressedData*)datasource)->data_pos;
155 }
156 
157 size_t VorbisLoader::file_read_func(void* ptr, size_t byte_size, size_t size_to_read, void* datasource)
158 {
159  C4MusicFileOgg *ogg = static_cast<C4MusicFileOgg *>(datasource);
160  size_t bytes_to_read = size_to_read*byte_size;
161  size_t bytes_read = 0u;
162  ogg->source_file.Read(ptr, bytes_to_read, &bytes_read);
163  return bytes_read / byte_size;
164 }
165 
166 int VorbisLoader::file_seek_func(void* datasource, ogg_int64_t offset, int whence)
167 {
168  C4MusicFileOgg *ogg = static_cast<C4MusicFileOgg *>(datasource);
169  return ogg->source_file.Seek(static_cast<long int>(offset), whence);
170 }
171 
172 int VorbisLoader::file_close_func(void* datasource)
173 {
174  C4MusicFileOgg *ogg = static_cast<C4MusicFileOgg *>(datasource);
175  ogg->source_file.Close();
176  return 1;
177 }
178 
179 long VorbisLoader::file_tell_func(void* datasource)
180 {
181  C4MusicFileOgg *ogg = static_cast<C4MusicFileOgg *>(datasource);
182  return ogg->source_file.Tell();
183 }
184 
185 bool VorbisLoader::ReadInfo(SoundInfo* result, BYTE* data, size_t data_length, uint32_t)
186 {
187  CompressedData compressed(data, data_length);
188 
189  int endian = 0;
190 
191  vorbis_info* info;
192  OggVorbis_File ogg_file;
193  memset(&ogg_file, 0, sizeof(ogg_file));
194  ov_callbacks callbacks;
195  callbacks.read_func = &mem_read_func;
196  callbacks.seek_func = &mem_seek_func;
197  callbacks.close_func = &mem_close_func;
198  callbacks.tell_func = &mem_tell_func;
199 
200  // open using callbacks
201  if (ov_open_callbacks(&compressed, &ogg_file, nullptr, 0, callbacks) != 0)
202  {
203  ov_clear(&ogg_file);
204  return false;
205  }
206 
207  // get information about sound
208  info = ov_info(&ogg_file, -1);
209  if (info->channels == 1)
210  result->format = AL_FORMAT_MONO16;
211  else
212  result->format = AL_FORMAT_STEREO16;
213  result->sample_rate = info->rate;
214  result->sample_length = ov_time_total(&ogg_file, -1)/1000.0;
215 
216  // Compute the total buffer size
217  const unsigned long total_size = static_cast<unsigned int>(result->sample_rate * result->sample_length * 1000.0 * info->channels * 2 + 0.5);
218  const unsigned long extra_size = 1024 * 8;
219 
220  // read: try to read the whole track in one go, and if there is more data
221  // than we predicted in total_size, read the additional data in 8K blocks.
222  unsigned long buffer_size = 0;
223  long bytes_read;
224  do {
225  const int chunk_size = total_size + extra_size - std::min(total_size, buffer_size);
226  int bitStream;
227  if (buffer_size+chunk_size > result->sound_data.size())
228  result->sound_data.resize(buffer_size+chunk_size);
229  bytes_read = ov_read(&ogg_file, (char*)&result->sound_data[buffer_size], chunk_size*sizeof(BYTE), endian, 2, 1, &bitStream);
230  buffer_size += bytes_read;
231  } while (bytes_read > 0);
232  result->sound_data.resize(buffer_size);
233 
234  // clear ogg file
235  ov_clear(&ogg_file);
236  return true;
237 }
238 
240 
241 #ifndef __APPLE__
242 bool WavLoader::ReadInfo(SoundInfo* result, BYTE* data, size_t data_length, uint32_t)
243 {
244  // load WAV resource
246  ALuint wav = alutCreateBufferFromFileImage((const ALvoid *)data, data_length);
247  if (wav == AL_NONE)
248  {
249  return false;
250  }
251 
252  // get information about sound
253  ALint freq, chans, bits, size;
254  alGetBufferi(wav, AL_FREQUENCY, &freq);
255  result->sample_rate = freq;
256  alGetBufferi(wav, AL_CHANNELS, &chans);
257  alGetBufferi(wav, AL_BITS, &bits);
258  alGetBufferi(wav, AL_SIZE, &size);
259  if (chans == 1)
260  if (bits == 8)
261  result->format = AL_FORMAT_MONO8;
262  else
263  result->format = AL_FORMAT_MONO16;
264  else
265  if (bits == 8)
266  result->format = AL_FORMAT_STEREO8;
267  else
268  result->format = AL_FORMAT_STEREO16;
269  // can't find any function to determine sample length
270  // just calc ourselves
271  result->sample_length = double(size) / double(bits*chans*freq/8);
272  // buffer loaded
273  result->final_handle = wav;
274  return true;
275 }
276 
278 #endif
279 
280 #elif AUDIO_TK == AUDIO_TK_SDL_MIXER
281 #define USE_RWOPS
282 #include <SDL_mixer.h>
283 
284 bool SDLMixerSoundLoader::ReadInfo(SoundInfo* result, BYTE* data, size_t data_length, uint32_t)
285 {
286  // Be paranoid about SDL_Mixer initialisation
288  { return false; }
289  SDL_RWops * rwops = SDL_RWFromConstMem(data, data_length);
290  // work around double free in SDL_Mixer by passing 0 here
291  result->final_handle = Mix_LoadWAV_RW(rwops, 0);
292  SDL_RWclose(rwops);
293  if (!result->final_handle)
294  { return false; }
295  //FIXME: Is this actually correct?
296  result->sample_length = result->final_handle->alen / (44100 * 2);
297  result->sample_rate = 0;
298  return true;
299 }
300 
301 SDLMixerSoundLoader SDLMixerSoundLoader::singleton;
302 
303 #endif
C4Application Application
Definition: C4Globals.cpp:44
uint8_t BYTE
C4MusicSystem MusicSystem
Definition: C4Application.h:41
bool IsMODInitialized()
Definition: C4MusicSystem.h:93
void SelectContext()
static SoundLoader * first_loader
bool ReadInfo(SoundInfo *result, BYTE *data, size_t data_length, uint32_t) override
static VorbisLoader singleton
static long file_tell_func(void *datasource)
static long mem_tell_func(void *datasource)
static int mem_close_func(void *datasource)
static int mem_seek_func(void *datasource, ogg_int64_t offset, int whence)
static int file_close_func(void *datasource)
static size_t file_read_func(void *ptr, size_t byte_size, size_t size_to_read, void *datasource)
static size_t mem_read_func(void *ptr, size_t byte_size, size_t size_to_read, void *datasource)
static int file_seek_func(void *datasource, ogg_int64_t offset, int whence)
static WavLoader singleton
bool ReadInfo(SoundInfo *result, BYTE *data, size_t data_length, uint32_t) override
std::vector< BYTE > sound_data