1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include "ac/file.h"
18 #include "util/wgt2allg.h"
19 #include "media/audio/soundcache.h"
20 #include "media/audio/audiointernaldefs.h"
21 #include "util/mutex.h"
22 #include "util/mutex_lock.h"
23 #include "util/string.h"
24 #include "debug/debugmanager.h"
25
26 using namespace Common;
27
28 sound_cache_entry_t* sound_cache_entries = NULL;
29 unsigned int sound_cache_counter = 0;
30
31 AGS::Engine::Mutex _sound_cache_mutex;
32
33
clear_sound_cache()34 void clear_sound_cache()
35 {
36 AGS::Engine::MutexLock _lock(_sound_cache_mutex);
37
38 if (sound_cache_entries)
39 {
40 int i;
41 for (i = 0; i < psp_audio_cachesize; i++)
42 {
43 if (sound_cache_entries[i].data)
44 {
45 free(sound_cache_entries[i].data);
46 sound_cache_entries[i].data = NULL;
47 free(sound_cache_entries[i].file_name);
48 sound_cache_entries[i].file_name = NULL;
49 sound_cache_entries[i].reference = 0;
50 }
51 }
52 }
53 else
54 {
55 sound_cache_entries = (sound_cache_entry_t*)malloc(psp_audio_cachesize * sizeof(sound_cache_entry_t));
56 memset(sound_cache_entries, 0, psp_audio_cachesize * sizeof(sound_cache_entry_t));
57 }
58 }
59
sound_cache_free(char * buffer,bool is_wave)60 void sound_cache_free(char* buffer, bool is_wave)
61 {
62 AGS::Engine::MutexLock _lock(_sound_cache_mutex);
63
64 #ifdef SOUND_CACHE_DEBUG
65 Debug::Printf("sound_cache_free(%p %d)\n", buffer, (unsigned int)is_wave);
66 #endif
67 int i;
68 for (i = 0; i < psp_audio_cachesize; i++)
69 {
70 if (sound_cache_entries[i].data == buffer)
71 {
72 if (sound_cache_entries[i].reference > 0)
73 sound_cache_entries[i].reference--;
74
75 #ifdef SOUND_CACHE_DEBUG
76 Debug::Printf("..decreased reference count of slot %d to %d\n", i, sound_cache_entries[i].reference);
77 #endif
78 return;
79 }
80 }
81
82 #ifdef SOUND_CACHE_DEBUG
83 Debug::Printf("..freeing uncached sound\n");
84 #endif
85
86 // Sound is uncached
87 if (i == psp_audio_cachesize)
88 {
89 if (is_wave)
90 destroy_sample((SAMPLE*)buffer);
91 else
92 free(buffer);
93 }
94 }
95
96
get_cached_sound(const AssetPath & asset_name,bool is_wave,long * size)97 char* get_cached_sound(const AssetPath &asset_name, bool is_wave, long* size)
98 {
99 AGS::Engine::MutexLock _lock(_sound_cache_mutex);
100
101 #ifdef SOUND_CACHE_DEBUG
102 Debug::Printf("get_cached_sound(%s %d)\n", asset_name.first.GetCStr(), (unsigned int)is_wave);
103 #endif
104
105 *size = 0;
106
107 int i;
108 for (i = 0; i < psp_audio_cachesize; i++)
109 {
110 if (sound_cache_entries[i].data == NULL)
111 continue;
112
113 if (strcmp(asset_name.second, sound_cache_entries[i].file_name) == 0)
114 {
115 #ifdef SOUND_CACHE_DEBUG
116 Debug::Printf("..found in slot %d\n", i);
117 #endif
118 sound_cache_entries[i].reference++;
119 sound_cache_entries[i].last_used = sound_cache_counter++;
120 *size = sound_cache_entries[i].size;
121
122 return sound_cache_entries[i].data;
123 }
124 }
125
126 // Not found
127 PACKFILE *mp3in = NULL;
128 SAMPLE* wave = NULL;
129
130 if (is_wave)
131 {
132 PACKFILE *wavin = PackfileFromAsset(asset_name);
133 if (wavin != NULL)
134 {
135 wave = load_wav_pf(wavin);
136 pack_fclose(wavin);
137 }
138 }
139 else
140 {
141 mp3in = PackfileFromAsset(asset_name);
142 if (mp3in == NULL)
143 {
144 return NULL;
145 }
146 }
147
148 // Find free slot
149 for (i = 0; i < psp_audio_cachesize; i++)
150 {
151 if (sound_cache_entries[i].data == NULL)
152 break;
153 }
154
155 // No free slot?
156 if (i == psp_audio_cachesize)
157 {
158 unsigned int oldest = sound_cache_counter;
159 int index = -1;
160
161 for (i = 0; i < psp_audio_cachesize; i++)
162 {
163 if (sound_cache_entries[i].reference == 0)
164 {
165 if (sound_cache_entries[i].last_used < oldest)
166 {
167 oldest = sound_cache_entries[i].last_used;
168 index = i;
169 }
170 }
171 }
172
173 i = index;
174 }
175
176 // Load new file
177 char* newdata;
178
179 if (is_wave)
180 {
181 *size = 0;
182 newdata = (char*)wave;
183 }
184 else
185 {
186 *size = mp3in->todo;
187 newdata = (char *)malloc(*size);
188
189 if (newdata == NULL)
190 {
191 pack_fclose(mp3in);
192 return NULL;
193 }
194
195 pack_fread(newdata, *size, mp3in);
196 pack_fclose(mp3in);
197 }
198
199 if (i == -1)
200 {
201 // No cache slot empty, return uncached data
202 #ifdef SOUND_CACHE_DEBUG
203 Debug::Printf("..loading uncached\n");
204 #endif
205 return newdata;
206 }
207 else
208 {
209 // Add to cache, free old sound first
210 #ifdef SOUND_CACHE_DEBUG
211 Debug::Printf("..loading cached in slot %d\n", i);
212 #endif
213
214 if (sound_cache_entries[i].data) {
215 if (sound_cache_entries[i].is_wave)
216 destroy_sample((SAMPLE*)sound_cache_entries[i].data);
217 else
218 free(sound_cache_entries[i].data);
219 }
220
221 sound_cache_entries[i].size = *size;
222 sound_cache_entries[i].data = newdata;
223
224 if (sound_cache_entries[i].file_name)
225 free(sound_cache_entries[i].file_name);
226 sound_cache_entries[i].file_name = (char*)malloc(strlen(asset_name.second) + 1);
227 strcpy(sound_cache_entries[i].file_name, asset_name.second);
228 sound_cache_entries[i].reference = 1;
229 sound_cache_entries[i].last_used = sound_cache_counter++;
230 sound_cache_entries[i].is_wave = is_wave;
231
232 return sound_cache_entries[i].data;
233 }
234
235 }
236