@@ -51,16 +51,32 @@ namespace cage
5151 {
5252 Holder<VoicesMixer> mixer;
5353 Holder<Voice> chaining; // register this mixer in the engine scene mixer
54+ ankerl::unordered_dense::map<uintPtr, Holder<Voice>> voicesMapping; // must be destroyed before the mixer
55+ sint64 lastTime = 0 ;
56+ sint64 dispatchTime = 0 ;
5457
55- ankerl::unordered_dense::map<uintPtr, Holder<Voice>> voicesMapping;
58+ void process (const SoundCallbackData &data)
59+ {
60+ CAGE_ASSERT (mixer);
61+ // correction for time drift
62+ const sint64 period = controlThread ().updatePeriod ();
63+ const sint64 duration = sint64 (data.frames ) * 1'000'000 / data.sampleRate ;
64+ if (abs (lastTime - dispatchTime) > period)
65+ lastTime = dispatchTime; // reset time
66+ SoundCallbackData clb = data;
67+ clb.time = lastTime;
68+ lastTime += duration;
69+ dispatchTime += duration;
70+ mixer->process (clb);
71+ }
5672 };
5773
5874 struct SoundPrepareImpl
5975 {
6076 Holder<Mutex> mut = newMutex();
6177 std::vector<EmitListener> listeners;
6278 std::vector<EmitSound> sounds;
63- ankerl::unordered_dense::map<uintPtr, PrepareListener> listenersMapping;
79+ ankerl::unordered_dense::map<uintPtr, Holder< PrepareListener>> listenersMapping; // requires stable pointers
6480
6581 explicit SoundPrepareImpl (const EngineCreateConfig &config) {}
6682
@@ -138,20 +154,21 @@ namespace cage
138154 v->loop = e.sound .loop ;
139155 }
140156
141- void prepare (PrepareListener &l, const EmitListener &e)
157+ void prepare (PrepareListener &l, const EmitListener &e, uint64 dispatchTime )
142158 {
143159 { // listener
144160 if (!l.mixer )
145161 {
146162 l.mixer = newVoicesMixer ();
147163 l.chaining = engineSceneMixer ()->newVoice ();
148- l.chaining ->callback .bind <VoicesMixer , &VoicesMixer ::process>(+l. mixer );
164+ l.chaining ->callback .bind <PrepareListener , &PrepareListener ::process>(&l );
149165 }
150166 l.mixer ->orientation = e.transform .orientation ;
151167 l.mixer ->position = e.transform .position ;
152168 l.mixer ->maxActiveSounds = e.listener .maxSounds ;
153169 l.mixer ->maxGainThreshold = e.listener .maxGainThreshold ;
154170 l.mixer ->gain = e.listener .gain ;
171+ l.dispatchTime = dispatchTime;
155172 }
156173
157174 { // remove obsolete
@@ -168,7 +185,7 @@ namespace cage
168185 prepare (l, l.voicesMapping [s.id ], s);
169186 }
170187
171- void dispatch (uint64 time )
188+ void dispatch (uint64 dispatchTime )
172189 {
173190 auto lock = ScopeLock (mut);
174191
@@ -181,11 +198,16 @@ namespace cage
181198 }
182199
183200 for (const EmitListener &e : listeners)
184- prepare (listenersMapping[e.id ], e);
201+ {
202+ Holder<PrepareListener> &h = listenersMapping[e.id ];
203+ if (!h)
204+ h = systemMemory ().createHolder <PrepareListener>();
205+ prepare (*h, e, dispatchTime);
206+ }
185207
186208 {
187209 ProfilingScope profiling (" speaker process" );
188- engineSpeaker ()->process (time, controlThread ().updatePeriod ());
210+ engineSpeaker ()->process (controlThread ().updatePeriod ());
189211 }
190212 }
191213 };
@@ -198,9 +220,9 @@ namespace cage
198220 soundPrepare->emit ();
199221 }
200222
201- void soundDispatch (uint64 time )
223+ void soundDispatch (uint64 dispatchTime )
202224 {
203- soundPrepare->dispatch (time );
225+ soundPrepare->dispatch (dispatchTime );
204226 }
205227
206228 void soundFinalize ()
0 commit comments