1 module prova.assets.audio.audioclip;
2 
3 import derelict.openal.al;
4 import derelict.vorbis;
5 import prova.assets;
6 import std.string;
7 
8 /// Only supports ogg for now
9 final class AudioClip : Asset
10 {
11   /// What distance in units equals one meter (defaults to 1)
12   static float scale = 1;
13   ///
14   package(prova) uint bufferId;
15   private uint _channels;
16 
17   ///
18   this(string path)
19   {
20     genFromOgg(path);
21   }
22 
23   ///
24   @property uint channels()
25   {
26     return _channels;
27   }
28 
29   private void genFromOgg(string path)
30   {
31     OggVorbis_File ogg;
32 
33     if(ov_fopen(toStringz(path), &ogg) < 0)
34       throw new Exception("\"" ~ path ~ "\" is not a valid Ogg file");
35 
36     const BUFFER_SIZE = 4096;
37     byte[BUFFER_SIZE] dataBuffer;
38     byte[] data;
39     long bytesRead = 0;
40     int currentSection;
41 
42     long requiredCapacity = ov_pcm_total(&ogg, -1) * ogg.vi.channels * 2;
43     data.reserve(requiredCapacity);
44 
45     do{
46       bytesRead = ov_read(&ogg, dataBuffer.ptr, BUFFER_SIZE, 0, 2, 1, &currentSection);
47 
48       data ~= dataBuffer[0 .. bytesRead];
49     }
50     while(bytesRead > 0);
51 
52     genBuffer(ogg.vi.channels, data, ogg.vi.rate);
53 
54     ov_clear(&ogg);
55   }
56 
57   private void genBuffer(uint channels, byte[] data, int frequency)
58   {
59     _channels = channels;
60 
61     ALenum format = channels ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
62 
63     alGenBuffers(1, &bufferId);
64     alBufferData(bufferId, format, data.ptr, cast(int) data.length, frequency);
65   }
66 }