55
66#include " gus.h"
77
8+ #define GUS_ALLOC_DEBUG_LOG 0
9+
810MinialGUS::MinialGUS (ALint monoSources)
911{
1012 m_gusVoices = monoSources;
@@ -70,6 +72,7 @@ uint32_t MinialGUS::gusAlloc(uint32_t len)
7072 uint32_t oldStart = fm.first ;
7173 freeMap.erase (oldStart);
7274 freeMap[oldStart + len] = oldLen - len;
75+ allocMap[oldStart] = len;
7376 return oldStart;
7477 }
7578 }
@@ -82,7 +85,57 @@ void MinialGUS::gusFree(uint32_t pos)
8285 {
8386 return ;
8487 }
85- /* TODO*/
88+ auto it = allocMap.find (pos);
89+ if (it == allocMap.end ())
90+ {
91+ return ;
92+ }
93+ freeMap[it->first ] = it->second ;
94+ allocMap.erase (pos);
95+ gusDefrag ();
96+ }
97+
98+ void MinialGUS::gusDefrag (void )
99+ {
100+ for (;;)
101+ {
102+ uint32_t thisAddr = 0 ;
103+ uint32_t nextAddr = 0 ;
104+ uint32_t newLen = 0 ;
105+ bool found = false ;
106+ for (auto it : freeMap)
107+ {
108+ nextAddr = it.first + it.second ;
109+ auto it2 = freeMap.find (nextAddr);
110+ if (nextAddr % 262144 != 0 && it2 != freeMap.end ())
111+ {
112+ found = true ;
113+ thisAddr = it.first ;
114+ newLen = it.second + it2->second ;
115+ break ;
116+ }
117+ }
118+ if (!found)
119+ {
120+ break ;
121+ }
122+ freeMap[thisAddr] = newLen;
123+ freeMap.erase (nextAddr);
124+ }
125+ #if GUS_ALLOC_DEBUG_LOG
126+ printf (" defrag[" );
127+ bool first = true ;
128+ for (auto it : freeMap)
129+ {
130+ if (!first)
131+ {
132+ printf (" |" );
133+ }
134+ printf (" %x %x" , it.first , it.first + it.second );
135+ first = false ;
136+ }
137+ printf (" ]\n " );
138+ #endif
86139}
87140
88141void MinialGUS::gusSetVolume (uint8_t voice, ALfloat listenerGain, ALfloat sourceGain)
@@ -135,12 +188,29 @@ void MinialGUS::DeleteSources(ALsizei n, const ALuint* sources)
135188 if (sources[i] > 0 && sources[i] <= (ALuint)m_gusVoices)
136189 {
137190 sourceMap[sources[i] - 1 ].alloc = false ;
191+ if (sourceMap[sources[i] - 1 ].buffer )
192+ {
193+ auto it = bufferMap.find (sourceMap[sources[i] - 1 ].buffer );
194+ if (it != bufferMap.end ())
195+ {
196+ MA_GUS_Buffer& buf = it->second ;
197+ --buf.refcount ;
198+ }
199+ }
138200 }
139201 }
140202}
141203void MinialGUS::DeleteBuffers (ALsizei n, const ALuint* buffers)
142204{
143- for (int i = 0 ; i != n; ++i)
205+ for (ALsizei i = 0 ; i != n; ++i)
206+ {
207+ if (bufferMap[buffers[i]].refcount != 0 )
208+ {
209+ m_error = AL_INVALID_OPERATION;
210+ return ;
211+ }
212+ }
213+ for (ALsizei i = 0 ; i != n; ++i)
144214 {
145215 gusFree (bufferMap[buffers[i]].addr );
146216 }
@@ -162,7 +232,22 @@ void MinialGUS::BufferData(ALuint buffer, ALenum format, const ALvoid* data, ALs
162232 MA_GUS_Buffer& buff = bufferMap[buffer];
163233 buff.pitch = float (freq) / float (m_freq);
164234
235+ gusFree (buff.addr );
165236 buff.addr = gusAlloc (size);
237+ #if GUS_ALLOC_DEBUG_LOG
238+ printf (" alloc[" );
239+ bool first = true ;
240+ for (auto it : freeMap)
241+ {
242+ if (!first)
243+ {
244+ printf (" |" );
245+ }
246+ printf (" %x %x" , it.first , it.first + it.second );
247+ first = false ;
248+ }
249+ printf (" ]\n " );
250+ #endif
166251 if (buff.addr != GUS_INVALID_ALLOC)
167252 {
168253 buff.len = size;
@@ -171,6 +256,10 @@ void MinialGUS::BufferData(ALuint buffer, ALenum format, const ALvoid* data, ALs
171256 GUSPoke (buff.addr + i, ((int16_t *)data)[i] / 256 );
172257 }
173258 }
259+ else
260+ {
261+ m_error = AL_OUT_OF_MEMORY;
262+ }
174263}
175264void MinialGUS::Sourcef (ALuint source, ALenum param, ALfloat value)
176265{
@@ -260,6 +349,26 @@ void MinialGUS::Sourcei(ALuint source, ALenum param, ALint value)
260349 }
261350 else
262351 {
352+ if (src.buffer )
353+ {
354+ auto it = bufferMap.find (src.buffer );
355+ if (it != bufferMap.end ())
356+ {
357+ MA_GUS_Buffer& buf = it->second ;
358+ --buf.refcount ;
359+ }
360+ }
361+ if (value)
362+ {
363+ auto it = bufferMap.find (value);
364+ if (it == bufferMap.end ())
365+ {
366+ m_error = AL_INVALID_NAME;
367+ return ;
368+ }
369+ MA_GUS_Buffer& buf = it->second ;
370+ ++buf.refcount ;
371+ }
263372 src.buffer = value;
264373 }
265374 break ;
0 commit comments