@@ -11,7 +11,161 @@ import bindbc.openal;
1111
1212import zyeware.common;
1313import zyeware.audio;
14+ import zyeware.audio.thread;
1415
16+ class AudioSource
17+ {
18+ private :
19+ static const (ubyte )[] sEmptyData = new ubyte [0 ];
20+
21+ protected :
22+ enum State
23+ {
24+ stopped,
25+ paused,
26+ playing
27+ }
28+
29+ // TODO: Add engine-wide buffer size settings
30+ enum bufferSize = 4096 * 4 ;
31+ enum bufferCount = 4 ;
32+
33+ float [] mProcBuffer;
34+
35+ AudioStream mAudioStream;
36+ AudioDecoder mDecoder;
37+ uint mSourceId;
38+ uint [] mBufferIDs;
39+ int mProcessed;
40+
41+ State mState;
42+ bool mLooping; // TODO: Maybe add loop point?
43+ AudioBus mBus;
44+
45+ package (zyeware):
46+ void updateBuffers ()
47+ {
48+ if (mState == State.stopped)
49+ return ;
50+
51+ long lastReadLength;
52+ int processed;
53+ uint pBuf;
54+ alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED , &processed);
55+
56+ while (processed-- )
57+ {
58+ alSourceUnqueueBuffers(mSourceId, 1 , &pBuf);
59+
60+ lastReadLength = mDecoder.read(mProcBuffer);
61+
62+ if (lastReadLength <= 0 )
63+ {
64+ if (mLooping)
65+ {
66+ mDecoder.seekTo(0 ); // TODO: Replace with a loop point
67+ lastReadLength = mDecoder.read(mProcBuffer);
68+ }
69+ else
70+ break ;
71+ }
72+
73+ alBufferData(pBuf, mDecoder.channels == 1 ? AL_FORMAT_MONO_FLOAT32 : AL_FORMAT_STEREO_FLOAT32 ,
74+ &mProcBuffer[0 ], cast (int ) (lastReadLength * float .sizeof), cast (int ) mDecoder.sampleRate);
75+
76+ alSourceQueueBuffers(mSourceId, 1 , &pBuf);
77+ }
78+
79+ int buffersQueued;
80+ alGetSourcei(mSourceId, AL_BUFFERS_QUEUED , &buffersQueued);
81+ if (buffersQueued == 0 )
82+ stop();
83+ }
84+
85+ public :
86+ this (AudioBus bus = null )
87+ {
88+ mBus = bus ? bus : AudioAPI.getBus(" master" );
89+
90+ mProcBuffer = new float [bufferSize];
91+ mBufferIDs = new uint [bufferCount];
92+
93+ alGenSources(1 , &mSourceId);
94+ alGenBuffers(cast (int ) mBufferIDs.length, &mBufferIDs[0 ]);
95+
96+ AudioThread.register(this );
97+ }
98+
99+ ~this ()
100+ {
101+ AudioThread.unregister(this );
102+
103+ destroy ! false (mDecoder);
104+
105+ alDeleteBuffers(cast (int ) mBufferIDs.length, &mBufferIDs[0 ]);
106+ alDeleteSources(1 , &mSourceId);
107+ }
108+
109+ void play ()
110+ {
111+ if (mState == State.playing)
112+ stop();
113+
114+ if (mState == State.stopped)
115+ {
116+ long lastReadLength;
117+ for (size_t i; i < bufferCount; ++ i)
118+ {
119+ lastReadLength = mDecoder.read(mProcBuffer);
120+ alBufferData(mBufferIDs[i], mDecoder.channels == 1 ? AL_FORMAT_MONO_FLOAT32 : AL_FORMAT_STEREO_FLOAT32 ,
121+ &mProcBuffer[0 ], cast (int ) (lastReadLength * float .sizeof), cast (int ) mDecoder.sampleRate);
122+ alSourceQueueBuffers(mSourceId, 1 , &mBufferIDs[i]);
123+ }
124+ }
125+
126+ mState = State.playing;
127+ alSourcePlay(mSourceId);
128+ }
129+
130+ void pause ()
131+ {
132+ mState = State.paused;
133+ alSourcePause(mSourceId);
134+ }
135+
136+ void stop ()
137+ {
138+ mState = State.stopped;
139+ alSourceStop(mSourceId);
140+
141+ mDecoder.seekTo(0 );
142+
143+ int bufferCount;
144+ alGetSourcei(mSourceId, AL_BUFFERS_QUEUED , &bufferCount);
145+
146+ for (size_t i; i < bufferCount; ++ i)
147+ {
148+ uint removedBuffer;
149+ alSourceUnqueueBuffers(mSourceId, 1 , &removedBuffer);
150+ }
151+ }
152+
153+ inout (AudioStream) stream () inout nothrow
154+ {
155+ return mAudioStream;
156+ }
157+
158+ void stream (AudioStream value)
159+ {
160+ if (mState != State.stopped)
161+ stop();
162+
163+ mAudioStream = value;
164+ mDecoder.setData(mAudioStream.encodedMemory);
165+ }
166+ }
167+
168+ /*
15169class AudioSource
16170{
17171protected:
@@ -113,4 +267,4 @@ public:
113267 {
114268 alSourcei(mId, AL_LOOPING, value);
115269 }
116- }
270+ }*/
0 commit comments