1 module prova.attachables.audio.audiosource;
2 
3 import derelict.openal.al;
4 import prova.assets;
5 import prova.audio;
6 import prova.core;
7 import prova.entities;
8 import prova.math;
9 
10 /// 
11 class AudioSource
12 {
13   private uint sourceId;
14   private AudioClip audioClip;
15   private Entity _entity;
16   private bool _looping = false;
17   private float _volume = 1;
18   private float _pitch = 1;
19 
20   /// Limited to Ogg files for now
21   this(AudioClip audioClip)
22   {
23     this.audioClip = audioClip;
24 
25     alGenSources(1, &sourceId);
26     alSourcei(sourceId, AL_BUFFER, audioClip.bufferId);
27   }
28 
29   ///
30   @property Entity entity()
31   {
32     return _entity;
33   }
34 
35   ///
36   @property void entity(Entity entity)
37   {
38     _entity = entity;
39   }
40 
41   ///
42   @property uint channels()
43   {
44     return audioClip.channels;
45   }
46 
47   ///
48   @property float volume()
49   {
50     return _volume;
51   }
52 
53   ///
54   @property void volume(float value)
55   {
56     _volume = value;
57     alSourcef(sourceId, AL_GAIN, value);
58   }
59 
60   ///
61   @property float pitch()
62   {
63     return _pitch;
64   }
65 
66   ///
67   @property void pitch(float value)
68   {
69     _pitch = value;
70     alSourcef(sourceId, AL_PITCH, value);
71   }
72 
73   ///
74   @property bool isPlaying()
75   {
76     ALenum status;
77     alGetSourcei(sourceId, AL_SOURCE_STATE, &status);
78 
79     return status == AL_PLAYING;
80   }
81 
82   ///
83   @property bool looping()
84   {
85     return _looping;
86   }
87 
88   ///
89   void play(bool loop = false)
90   {
91     if(isPlaying())
92       stop();
93 
94     _looping = loop;
95     alSourcei(sourceId, AL_LOOPING, loop);
96 
97     alSourceRewind(sourceId);
98     alSourcePlay(sourceId);
99   }
100 
101   ///
102   void stop()
103   {
104     alSourceStop(sourceId);
105   }
106 
107   ///
108   void pause()
109   {
110     alSourcePause(sourceId);
111   }
112 
113   ///
114   void resume()
115   {
116     alSourcePlay(sourceId);
117   }
118 
119   package(prova) void update()
120   {
121     if(!entity)
122       return;
123 
124     Vector3 position = entity.getWorldPosition();
125     Vector3 velocity = entity.getWorldRotation() * entity.velocity;
126 
127     position /= Audio.scale;
128     velocity /= Audio.scale;
129 
130     alSource3f(sourceId, AL_POSITION, position.x, position.y, position.z);
131     alSource3f(sourceId, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
132   }
133 
134   ~this()
135   {
136     if(isPlaying)
137       stop();
138 
139     alDeleteSources(1, &sourceId);
140   }
141 }