1 /* FluidSynth - A Software Synthesizer
3 * Copyright (C) 2003 Peter Hanappe and others.
5 * SoundFont file loading code borrowed from Smurf SoundFont Editor
6 * Copyright (C) 1999-2001 Josh Green
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.
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.
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
24 /* CACHED SAMPLE DATA LOADER
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.
30 #include "fluid_samplecache.h"
31 #include "fluid_sys.h"
32 #include "fluidsynth.h"
33 #include "fluid_list.h"
36 typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
38 struct _fluid_samplecache_entry_t
40 /* The follwing members all form the cache key */
42 time_t modification_time;
43 unsigned int sf_samplepos;
44 unsigned int sf_samplesize;
45 unsigned int sf_sample24pos;
46 unsigned int sf_sample24size;
47 unsigned int sample_start;
48 unsigned int sample_end;
50 /* End of cache key members */
60 static fluid_list_t *samplecache_list = NULL;
61 static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
63 static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
64 static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
65 static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
67 static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
70 /* PUBLIC INTERFACE */
72 int fluid_samplecache_load(SFData *sf,
73 unsigned int sample_start, unsigned int sample_end, int sample_type,
74 int try_mlock, short **sample_data, char **sample_data24)
76 fluid_samplecache_entry_t *entry;
79 fluid_mutex_lock(samplecache_mutex);
81 entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type);
85 entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type);
93 samplecache_list = fluid_list_prepend(samplecache_list, entry);
96 if(try_mlock && !entry->mlocked)
98 /* Lock the memory to disable paging. It's okay if this fails. It
99 * probably means that the user doesn't have the required permission. */
100 if(fluid_mlock(entry->sample_data, entry->sample_count * sizeof(short)) == 0)
102 if(entry->sample_data24 != NULL)
104 entry->mlocked = (fluid_mlock(entry->sample_data24, entry->sample_count) == 0);
108 entry->mlocked = TRUE;
113 fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
114 FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
119 entry->num_references++;
120 *sample_data = entry->sample_data;
121 *sample_data24 = entry->sample_data24;
122 ret = entry->sample_count;
125 fluid_mutex_unlock(samplecache_mutex);
129 int fluid_samplecache_unload(const short *sample_data)
131 fluid_list_t *entry_list;
132 fluid_samplecache_entry_t *entry;
135 fluid_mutex_lock(samplecache_mutex);
137 entry_list = samplecache_list;
141 entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
143 if(sample_data == entry->sample_data)
145 entry->num_references--;
147 if(entry->num_references == 0)
151 fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
153 if(entry->sample_data24 != NULL)
155 fluid_munlock(entry->sample_data24, entry->sample_count);
159 samplecache_list = fluid_list_remove(samplecache_list, entry);
160 delete_samplecache_entry(entry);
167 entry_list = fluid_list_next(entry_list);
170 FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache.");
174 fluid_mutex_unlock(samplecache_mutex);
179 /* Private functions */
180 static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
181 unsigned int sample_start,
182 unsigned int sample_end,
185 fluid_samplecache_entry_t *entry;
187 entry = FLUID_NEW(fluid_samplecache_entry_t);
191 FLUID_LOG(FLUID_ERR, "Out of memory");
195 FLUID_MEMSET(entry, 0, sizeof(*entry));
197 entry->filename = FLUID_STRDUP(sf->fname);
199 if(entry->filename == NULL)
201 FLUID_LOG(FLUID_ERR, "Out of memory");
205 if(fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
207 FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
208 entry->modification_time = 0;
211 entry->sf_samplepos = sf->samplepos;
212 entry->sf_samplesize = sf->samplesize;
213 entry->sf_sample24pos = sf->sample24pos;
214 entry->sf_sample24size = sf->sample24size;
215 entry->sample_start = sample_start;
216 entry->sample_end = sample_end;
217 entry->sample_type = sample_type;
219 entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type,
220 &entry->sample_data, &entry->sample_data24);
222 if(entry->sample_count < 0)
230 delete_samplecache_entry(entry);
234 static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
236 fluid_return_if_fail(entry != NULL);
238 FLUID_FREE(entry->filename);
239 FLUID_FREE(entry->sample_data);
240 FLUID_FREE(entry->sample_data24);
244 static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
245 unsigned int sample_start,
246 unsigned int sample_end,
250 fluid_list_t *entry_list;
251 fluid_samplecache_entry_t *entry;
253 if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
255 FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
259 entry_list = samplecache_list;
263 entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
265 if((FLUID_STRCMP(sf->fname, entry->filename) == 0) &&
266 (mtime == entry->modification_time) &&
267 (sf->samplepos == entry->sf_samplepos) &&
268 (sf->samplesize == entry->sf_samplesize) &&
269 (sf->sample24pos == entry->sf_sample24pos) &&
270 (sf->sample24size == entry->sf_sample24size) &&
271 (sample_start == entry->sample_start) &&
272 (sample_end == entry->sample_end) &&
273 (sample_type == entry->sample_type))
278 entry_list = fluid_list_next(entry_list);
284 static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
286 fluid_stat_buf_t buf;
288 if(fluid_stat(filename, &buf))
293 *modification_time = buf.st_mtime;