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