Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/fluidsynth/src/sfloader/fluid_samplecache.c
4396 views
1
/* FluidSynth - A Software Synthesizer
2
*
3
* Copyright (C) 2003 Peter Hanappe and others.
4
*
5
* SoundFont file loading code borrowed from Smurf SoundFont Editor
6
* Copyright (C) 1999-2001 Josh Green
7
*
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public License
10
* as published by the Free Software Foundation; either version 2.1 of
11
* the License, or (at your option) any later version.
12
*
13
* This library is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
17
*
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free
20
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
* 02110-1301, USA
22
*/
23
24
/* CACHED SAMPLE DATA LOADER
25
*
26
* This is a wrapper around fluid_sffile_read_sample_data that attempts to cache the read
27
* data across all FluidSynth instances in a global (process-wide) list.
28
*/
29
30
#include "fluid_samplecache.h"
31
#include "fluid_sys.h"
32
#include "fluid_list.h"
33
34
35
typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
36
37
struct _fluid_samplecache_entry_t
38
{
39
/* The following members all form the cache key */
40
char *filename;
41
time_t modification_time;
42
unsigned int sf_samplepos;
43
unsigned int sf_samplesize;
44
unsigned int sf_sample24pos;
45
unsigned int sf_sample24size;
46
unsigned int sample_start;
47
unsigned int sample_end;
48
int sample_type;
49
/* End of cache key members */
50
51
short *sample_data;
52
char *sample_data24;
53
int sample_count;
54
55
int num_references;
56
int mlocked;
57
};
58
59
static fluid_list_t *samplecache_list = NULL;
60
static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
61
62
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start,
63
unsigned int sample_end, int sample_type, time_t mtime);
64
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start,
65
unsigned int sample_end, int sample_type, time_t mtime);
66
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
67
68
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
69
70
71
/* PUBLIC INTERFACE */
72
73
int fluid_samplecache_load(SFData *sf,
74
unsigned int sample_start, unsigned int sample_end, int sample_type,
75
int try_mlock, short **sample_data, char **sample_data24)
76
{
77
fluid_samplecache_entry_t *entry;
78
int ret;
79
time_t mtime;
80
81
fluid_mutex_lock(samplecache_mutex);
82
83
if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
84
{
85
mtime = 0;
86
}
87
88
entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
89
90
if(entry == NULL)
91
{
92
fluid_mutex_unlock(samplecache_mutex);
93
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
94
95
if(entry == NULL)
96
{
97
ret = -1;
98
goto unlock_exit;
99
}
100
101
fluid_mutex_lock(samplecache_mutex);
102
samplecache_list = fluid_list_prepend(samplecache_list, entry);
103
}
104
fluid_mutex_unlock(samplecache_mutex);
105
106
if(try_mlock && !entry->mlocked)
107
{
108
/* Lock the memory to disable paging. It's okay if this fails. It
109
* probably means that the user doesn't have the required permission. */
110
if(fluid_mlock(entry->sample_data, entry->sample_count * sizeof(short)) == 0)
111
{
112
if(entry->sample_data24 != NULL)
113
{
114
entry->mlocked = (fluid_mlock(entry->sample_data24, entry->sample_count) == 0);
115
}
116
else
117
{
118
entry->mlocked = TRUE;
119
}
120
121
if(!entry->mlocked)
122
{
123
fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
124
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
125
}
126
}
127
}
128
129
entry->num_references++;
130
*sample_data = entry->sample_data;
131
*sample_data24 = entry->sample_data24;
132
ret = entry->sample_count;
133
134
unlock_exit:
135
return ret;
136
}
137
138
int fluid_samplecache_unload(const short *sample_data)
139
{
140
fluid_list_t *entry_list;
141
fluid_samplecache_entry_t *entry;
142
int ret;
143
144
fluid_mutex_lock(samplecache_mutex);
145
146
entry_list = samplecache_list;
147
148
while(entry_list)
149
{
150
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
151
152
if(sample_data == entry->sample_data)
153
{
154
entry->num_references--;
155
156
if(entry->num_references == 0)
157
{
158
if(entry->mlocked)
159
{
160
fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
161
162
if(entry->sample_data24 != NULL)
163
{
164
fluid_munlock(entry->sample_data24, entry->sample_count);
165
}
166
}
167
168
samplecache_list = fluid_list_remove(samplecache_list, entry);
169
delete_samplecache_entry(entry);
170
}
171
172
ret = FLUID_OK;
173
goto unlock_exit;
174
}
175
176
entry_list = fluid_list_next(entry_list);
177
}
178
179
FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache.");
180
ret = FLUID_FAILED;
181
182
unlock_exit:
183
fluid_mutex_unlock(samplecache_mutex);
184
return ret;
185
}
186
187
188
/* Private functions */
189
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
190
unsigned int sample_start,
191
unsigned int sample_end,
192
int sample_type,
193
time_t mtime)
194
{
195
fluid_samplecache_entry_t *entry;
196
197
entry = FLUID_NEW(fluid_samplecache_entry_t);
198
199
if(entry == NULL)
200
{
201
FLUID_LOG(FLUID_ERR, "Out of memory");
202
return NULL;
203
}
204
205
FLUID_MEMSET(entry, 0, sizeof(*entry));
206
207
entry->filename = FLUID_STRDUP(sf->fname);
208
209
if(entry->filename == NULL)
210
{
211
FLUID_LOG(FLUID_ERR, "Out of memory");
212
goto error_exit;
213
}
214
215
entry->sf_samplepos = sf->samplepos;
216
entry->sf_samplesize = sf->samplesize;
217
entry->sf_sample24pos = sf->sample24pos;
218
entry->sf_sample24size = sf->sample24size;
219
entry->sample_start = sample_start;
220
entry->sample_end = sample_end;
221
entry->sample_type = sample_type;
222
entry->modification_time = mtime;
223
224
entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type,
225
&entry->sample_data, &entry->sample_data24);
226
227
if(entry->sample_count < 0)
228
{
229
goto error_exit;
230
}
231
232
return entry;
233
234
error_exit:
235
delete_samplecache_entry(entry);
236
return NULL;
237
}
238
239
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
240
{
241
fluid_return_if_fail(entry != NULL);
242
243
FLUID_FREE(entry->filename);
244
FLUID_FREE(entry->sample_data);
245
FLUID_FREE(entry->sample_data24);
246
FLUID_FREE(entry);
247
}
248
249
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
250
unsigned int sample_start,
251
unsigned int sample_end,
252
int sample_type,
253
time_t mtime)
254
{
255
fluid_list_t *entry_list;
256
fluid_samplecache_entry_t *entry;
257
258
entry_list = samplecache_list;
259
260
while(entry_list)
261
{
262
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
263
264
if((FLUID_STRCMP(sf->fname, entry->filename) == 0) &&
265
(mtime == entry->modification_time) &&
266
(sf->samplepos == entry->sf_samplepos) &&
267
(sf->samplesize == entry->sf_samplesize) &&
268
(sf->sample24pos == entry->sf_sample24pos) &&
269
(sf->sample24size == entry->sf_sample24size) &&
270
(sample_start == entry->sample_start) &&
271
(sample_end == entry->sample_end) &&
272
(sample_type == entry->sample_type))
273
{
274
return entry;
275
}
276
277
entry_list = fluid_list_next(entry_list);
278
}
279
280
return NULL;
281
}
282
283
static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
284
{
285
fluid_stat_buf_t buf;
286
287
if(fluid_stat(filename, &buf))
288
{
289
return FLUID_FAILED;
290
}
291
292
*modification_time = buf.st_mtime;
293
return FLUID_OK;
294
}
295
296
297
/* Only used for tests */
298
int fluid_samplecache_count_entries(void)
299
{
300
fluid_list_t *entry;
301
int count = 0;
302
303
fluid_mutex_lock(samplecache_mutex);
304
305
for(entry = samplecache_list; entry != NULL; entry = fluid_list_next(entry))
306
{
307
count++;
308
}
309
310
fluid_mutex_unlock(samplecache_mutex);
311
312
return count;
313
}
314
315