1 /*
2 * libInstPatch
3 * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; version 2.1
8 * of the License only.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA or on the web at http://www.gnu.org.
19 */
20 /**
21 * SECTION: IpatchSampleStoreRam
22 * @short_description: Sample store object for audio data in RAM
23 * @see_also:
24 * @stability: Stable
25 */
26 #include <string.h>
27 #include <stdlib.h>
28 #include <glib.h>
29 #include <glib-object.h>
30 #include "IpatchSampleStoreRam.h"
31 #include "ipatch_priv.h"
32 #include "i18n.h"
33
34 /* properties */
35 enum
36 {
37 PROP_0,
38 PROP_LOCATION,
39 PROP_FREE_DATA
40 };
41
42
43 static void ipatch_sample_store_ram_sample_iface_init(IpatchSampleIface *iface);
44 static void ipatch_sample_store_ram_set_property
45 (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
46 static void ipatch_sample_store_ram_get_property
47 (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
48 static void ipatch_sample_store_ram_finalize(GObject *object);
49 static gboolean ipatch_sample_store_ram_sample_iface_open
50 (IpatchSampleHandle *handle, GError **err);
51 static gboolean ipatch_sample_store_ram_sample_iface_read
52 (IpatchSampleHandle *handle, guint offset, guint frames, gpointer buf, GError **err);
53 static gboolean ipatch_sample_store_ram_sample_iface_write
54 (IpatchSampleHandle *handle, guint offset, guint frames, gconstpointer buf, GError **err);
55
56
G_DEFINE_TYPE_WITH_CODE(IpatchSampleStoreRam,ipatch_sample_store_ram,IPATCH_TYPE_SAMPLE_STORE,G_IMPLEMENT_INTERFACE (IPATCH_TYPE_SAMPLE,ipatch_sample_store_ram_sample_iface_init))57 G_DEFINE_TYPE_WITH_CODE(IpatchSampleStoreRam, ipatch_sample_store_ram,
58 IPATCH_TYPE_SAMPLE_STORE,
59 G_IMPLEMENT_INTERFACE(IPATCH_TYPE_SAMPLE,
60 ipatch_sample_store_ram_sample_iface_init))
61
62 static void
63 ipatch_sample_store_ram_sample_iface_init(IpatchSampleIface *iface)
64 {
65 iface->open = ipatch_sample_store_ram_sample_iface_open;
66 iface->read = ipatch_sample_store_ram_sample_iface_read;
67 iface->write = ipatch_sample_store_ram_sample_iface_write;
68 }
69
70 static void
ipatch_sample_store_ram_class_init(IpatchSampleStoreRamClass * klass)71 ipatch_sample_store_ram_class_init(IpatchSampleStoreRamClass *klass)
72 {
73 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
74 IpatchItemClass *item_class = IPATCH_ITEM_CLASS(klass);
75
76 obj_class->finalize = ipatch_sample_store_ram_finalize;
77 obj_class->get_property = ipatch_sample_store_ram_get_property;
78 item_class->item_set_property = ipatch_sample_store_ram_set_property;
79
80 g_object_class_install_property(obj_class, PROP_LOCATION,
81 g_param_spec_pointer("location", "Location", "Sample data pointer",
82 G_PARAM_READWRITE));
83 g_object_class_install_property(obj_class, PROP_FREE_DATA,
84 g_param_spec_boolean("free-data", "Free data", "Free data when object destroyed",
85 FALSE, G_PARAM_READWRITE));
86 }
87
88 static void
ipatch_sample_store_ram_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)89 ipatch_sample_store_ram_set_property(GObject *object, guint property_id,
90 const GValue *value, GParamSpec *pspec)
91 {
92 IpatchSampleStoreRam *store = IPATCH_SAMPLE_STORE_RAM(object);
93
94 switch(property_id)
95 {
96 case PROP_LOCATION:
97 g_return_if_fail(store->location == NULL);
98
99 /* Lock not needed, should be set only once before use */
100 store->location = g_value_get_pointer(value);
101 break;
102
103 case PROP_FREE_DATA:
104 ipatch_item_set_flags(object, IPATCH_SAMPLE_STORE_RAM_ALLOCATED);
105 break;
106
107 default:
108 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
109 }
110 }
111
112 static void
ipatch_sample_store_ram_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)113 ipatch_sample_store_ram_get_property(GObject *object, guint property_id,
114 GValue *value, GParamSpec *pspec)
115 {
116 IpatchSampleStoreRam *store = IPATCH_SAMPLE_STORE_RAM(object);
117
118 switch(property_id)
119 {
120 case PROP_LOCATION:
121 /* Lock not needed, should be set only once before use */
122 g_value_set_pointer(value, store->location);
123 break;
124
125 case PROP_FREE_DATA:
126 g_value_set_boolean(value, (ipatch_item_get_flags((IpatchItem *)object)
127 & IPATCH_SAMPLE_STORE_RAM_ALLOCATED) != 0);
128 break;
129
130 default:
131 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
132 }
133 }
134
135 static void
ipatch_sample_store_ram_init(IpatchSampleStoreRam * store)136 ipatch_sample_store_ram_init(IpatchSampleStoreRam *store)
137 {
138 }
139
140 static void
ipatch_sample_store_ram_finalize(GObject * object)141 ipatch_sample_store_ram_finalize(GObject *object)
142 {
143 IpatchSampleStoreRam *store = IPATCH_SAMPLE_STORE_RAM(object);
144
145 if(ipatch_item_get_flags(IPATCH_ITEM(store)) & IPATCH_SAMPLE_STORE_RAM_ALLOCATED)
146 {
147 g_free(store->location);
148 store->location = NULL;
149 }
150
151 if(G_OBJECT_CLASS(ipatch_sample_store_ram_parent_class)->finalize)
152 {
153 G_OBJECT_CLASS(ipatch_sample_store_ram_parent_class)->finalize(object);
154 }
155 }
156
157 static gboolean
ipatch_sample_store_ram_sample_iface_open(IpatchSampleHandle * handle,GError ** err)158 ipatch_sample_store_ram_sample_iface_open(IpatchSampleHandle *handle,
159 GError **err)
160 {
161 IpatchSampleStoreRam *store = IPATCH_SAMPLE_STORE_RAM(handle->sample);
162 guint bytes;
163
164 g_return_val_if_fail(!handle->read_mode || store->location, FALSE);
165
166 /* Locking not needed, since new samples will be written with audio before
167 * being used by multiple threads */
168 if(!store->location)
169 {
170 ipatch_item_set_flags(IPATCH_ITEM(store), IPATCH_SAMPLE_STORE_RAM_ALLOCATED);
171 ipatch_sample_get_size(handle->sample, &bytes);
172 store->location = g_malloc0(bytes);
173 }
174
175 /* Store frame size to data1 */
176 handle->data1 = GUINT_TO_POINTER(ipatch_sample_format_size(ipatch_sample_store_get_format(store)));
177
178 return (TRUE);
179 }
180
181 static gboolean
ipatch_sample_store_ram_sample_iface_read(IpatchSampleHandle * handle,guint offset,guint frames,gpointer buf,GError ** err)182 ipatch_sample_store_ram_sample_iface_read(IpatchSampleHandle *handle,
183 guint offset, guint frames,
184 gpointer buf, GError **err)
185 {
186 IpatchSampleStoreRam *store = (IpatchSampleStoreRam *)(handle->sample);
187 guint8 frame_size = GPOINTER_TO_UINT(handle->data1);
188
189 /* No need to lock, sample data should not change after initial load */
190
191 memcpy(buf, &((gint8 *)(store->location))[offset * frame_size],
192 frames * frame_size);
193
194 return (TRUE);
195 }
196
197 static gboolean
ipatch_sample_store_ram_sample_iface_write(IpatchSampleHandle * handle,guint offset,guint frames,gconstpointer buf,GError ** err)198 ipatch_sample_store_ram_sample_iface_write(IpatchSampleHandle *handle,
199 guint offset, guint frames,
200 gconstpointer buf, GError **err)
201 {
202 IpatchSampleStoreRam *store = (IpatchSampleStoreRam *)(handle->sample);
203 guint8 frame_size = GPOINTER_TO_UINT(handle->data1);
204
205 /* No need to lock, sample data written only once and before used by
206 multiple threads */
207
208 memcpy(&((gint8 *)(store->location))[offset * frame_size], buf,
209 frames * frame_size);
210
211 return (TRUE);
212 }
213
214 /**
215 * ipatch_sample_store_ram_new:
216 * @location: (nullable): Location of existing sample data or %NULL if the sample buffer
217 * should be allocated (in which case the sample must be written to first).
218 * @free_data: %TRUE if sample data at @location should be freed when object
219 * is destroyed
220 *
221 * Creates a new RAM sample store.
222 *
223 * Returns: (type IpatchSampleStoreRam): New RAM sample store,
224 * cast as a #IpatchSample for convenience.
225 */
226 IpatchSample *
ipatch_sample_store_ram_new(gpointer location,gboolean free_data)227 ipatch_sample_store_ram_new(gpointer location, gboolean free_data)
228 {
229 return (IPATCH_SAMPLE(g_object_new(IPATCH_TYPE_SAMPLE_STORE_RAM,
230 "location", location,
231 "free-data", free_data,
232 NULL)));
233 }
234
235 /**
236 * ipatch_sample_store_ram_get_blank:
237 *
238 * Get blank mono RAM sample object. Return's a sample object
239 * with 48 stereo 16 bit samples of silent audio. Only creates it on
240 * the first call, subsequent calls return the same sample object. Therefore it
241 * should not be modified.
242 *
243 * Returns: (transfer full): The blank sample object. Remember to unref it when not
244 * using it anymore with g_object_unref().
245 */
246 IpatchSample *
ipatch_sample_store_ram_get_blank(void)247 ipatch_sample_store_ram_get_blank(void)
248 {
249 static IpatchSample *blank_sample = NULL;
250 gpointer dataptr;
251
252 if(!blank_sample)
253 {
254 dataptr = g_malloc(48 * 2);
255 blank_sample = ipatch_sample_store_ram_new(dataptr, TRUE);
256
257 g_object_set(blank_sample,
258 "sample-size", 48,
259 "sample-format", IPATCH_SAMPLE_16BIT | IPATCH_SAMPLE_ENDIAN_HOST,
260 "sample-rate", IPATCH_SAMPLE_RATE_DEFAULT,
261 NULL);
262 }
263 else
264 {
265 g_object_ref(blank_sample);
266 }
267
268 return (blank_sample);
269 }
270