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