/[svn]/linuxsampler/trunk/src/hostplugins/lv2/PluginLv2.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/hostplugins/lv2/PluginLv2.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2360 - (hide annotations) (download)
Thu Aug 16 17:01:35 2012 UTC (11 years, 8 months ago) by persson
File size: 11552 byte(s)
* LV2: fixed save/restore of SFZ state (patch by David Robillard)
* LV2: made LV2 plugin buildable on Windows and Mac

1 persson 1777 /***************************************************************************
2     * *
3 persson 2311 * Copyright (C) 2008 - 2012 Andreas Persson *
4 persson 1777 * *
5     * This program is free software; you can redistribute it and/or modify *
6     * it under the terms of the GNU General Public License as published by *
7     * the Free Software Foundation; either version 2 of the License, or *
8     * (at your option) any later version. *
9     * *
10     * This program 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 General Public License for more details. *
14     * *
15     * You should have received a copy of the GNU General Public License *
16     * along with this program; if not, write to the Free Software *
17     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18     * MA 02110-1301 USA *
19     ***************************************************************************/
20    
21 persson 2360 #define _BSD_SOURCE 1 /* for realpath() */
22    
23 persson 1777 #include <algorithm>
24 capela 2174 #include <cassert>
25 persson 1777 #include <cstdio>
26     #include <cstdlib>
27     #include <cstring>
28     #include <fstream>
29     #include <string>
30    
31     #include "PluginLv2.h"
32    
33 persson 2356 #include <lv2/lv2plug.in/ns/ext/atom/util.h>
34     #include <lv2/lv2plug.in/ns/ext/midi/midi.h>
35    
36 capela 2174 #define NS_LS "http://linuxsampler.org/schema#"
37    
38 persson 2356 #define CHANNELS 32
39    
40 persson 1777 namespace {
41    
42     PluginLv2::PluginLv2(const LV2_Descriptor* Descriptor,
43     double SampleRate, const char* BundlePath,
44     const LV2_Feature* const* Features) {
45 persson 2356 Out = new float*[CHANNELS];
46     for (int i = 0 ; i < CHANNELS ; i++) {
47     Out[i] = 0;
48     }
49 capela 2174 UriMap = 0;
50 capela 2291 MapPath = 0;
51     MakePath = 0;
52 persson 1777 for (int i = 0 ; Features[i] ; i++) {
53 schoenebeck 2304 dmsg(2, ("linuxsampler: init feature: %s\n", Features[i]->URI));
54 persson 2356 if (!strcmp(Features[i]->URI, LV2_URID__map)) {
55     UriMap = (LV2_URID_Map*)Features[i]->data;
56 capela 2340 } else if (!strcmp(Features[i]->URI, LV2_STATE__mapPath)) {
57 capela 2291 MapPath = (LV2_State_Map_Path*)Features[i]->data;
58 capela 2340 } else if (!strcmp(Features[i]->URI, LV2_STATE__makePath)) {
59 capela 2291 MakePath = (LV2_State_Make_Path*)Features[i]->data;
60 capela 2174 }
61 persson 1777 }
62    
63 persson 2356 MidiEventType = uri_to_id(LV2_MIDI__MidiEvent);
64 persson 1777
65 persson 2356 Init(SampleRate, 128, CHANNELS);
66    
67 persson 1777 InitState();
68 capela 2174
69     DefaultState = GetState();
70 persson 1777 }
71    
72 persson 2356 PluginLv2::~PluginLv2() {
73     delete[] Out;
74     }
75    
76 persson 1777 void PluginLv2::ConnectPort(uint32_t Port, void* DataLocation) {
77 persson 2356 if (Port == 0) {
78     MidiBuf = static_cast<LV2_Atom_Sequence*>(DataLocation);
79     } else if (Port < CHANNELS + 1) {
80     Out[Port - 1] = static_cast<float*>(DataLocation);
81 persson 1777 }
82     }
83    
84     void PluginLv2::Activate() {
85     dmsg(2, ("linuxsampler: Activate\n"));
86     }
87    
88     void PluginLv2::Run(uint32_t SampleCount) {
89     int samplePos = 0;
90 persson 2356
91     LV2_Atom_Event* ev = lv2_atom_sequence_begin(&MidiBuf->body);
92    
93 persson 1777 while (SampleCount) {
94     int samples = std::min(SampleCount, 128U);
95    
96 persson 2356 for ( ; !lv2_atom_sequence_is_end(&MidiBuf->body,
97     MidiBuf->atom.size, ev) ;
98     ev = lv2_atom_sequence_next(ev)) {
99     if (ev->body.type == MidiEventType) {
100 persson 1777
101 persson 2356 int time = ev->time.frames - samplePos;
102     if (time >= samples) break;
103 persson 1777
104 persson 2356 uint8_t* data = reinterpret_cast<uint8_t*>(ev + 1);
105 persson 1777
106 persson 2356 pMidiDevice->Port()->DispatchRaw(data, time);
107     }
108 persson 1777 }
109 persson 2356 for (int i = 0 ; i < CHANNELS ; i++) {
110     pAudioDevice->Channel(i)->SetBuffer(Out[i] + samplePos);
111     }
112 persson 1777 pAudioDevice->Render(samples);
113    
114     samplePos += samples;
115     SampleCount -= samples;
116     }
117     }
118    
119     void PluginLv2::Deactivate() {
120     dmsg(2, ("linuxsampler: Deactivate\n"));
121     }
122    
123 persson 2360 static String RealPath(const String& path)
124     {
125     String out = path;
126     char* cpath = NULL;
127     #ifdef _WIN32
128     cpath = (char*)malloc(MAX_PATH);
129     GetFullPathName(path.c_str(), MAX_PATH, cpath, NULL);
130     #else
131     cpath = realpath(path.c_str(), NULL);
132     #endif
133     if (cpath) {
134     out = cpath;
135     free(cpath);
136     }
137     return out;
138     }
139    
140 capela 2174 String PluginLv2::PathToState(const String& path) {
141 capela 2291 if (MapPath) {
142 schoenebeck 2304 char* cstr = MapPath->abstract_path(MapPath->handle, path.c_str());
143 capela 2174 const String abstract_path(cstr);
144     free(cstr);
145     return abstract_path;
146     }
147     return path;
148     }
149 persson 1777
150 capela 2174 String PluginLv2::PathFromState(const String& path) {
151 capela 2291 if (MapPath) {
152 schoenebeck 2304 char* cstr = MapPath->absolute_path(MapPath->handle, path.c_str());
153 persson 2360 // Resolve symbolic links so SFZ sample paths load correctly
154     const String absolute_path(RealPath(cstr));
155 capela 2174 free(cstr);
156 persson 2360 return absolute_path;
157 capela 2174 }
158     return path;
159     }
160 persson 1777
161 schoenebeck 2304 void PluginLv2::SetStateFeatures(const LV2_Feature* const* Features)
162     {
163     for (int i = 0 ; Features[i] ; i++) {
164     dmsg(2, ("linuxsampler: state feature: %s\n", Features[i]->URI));
165 capela 2340 if (!strcmp(Features[i]->URI, LV2_STATE__mapPath)) {
166 schoenebeck 2304 MapPath = (LV2_State_Map_Path*)Features[i]->data;
167 capela 2340 } else if (!strcmp(Features[i]->URI, LV2_STATE__makePath)) {
168 schoenebeck 2304 MakePath = (LV2_State_Make_Path*)Features[i]->data;
169     }
170     }
171     }
172 persson 1777
173 capela 2340 LV2_State_Status PluginLv2::Save(
174 persson 2356 LV2_State_Store_Function store, LV2_State_Handle handle,
175     uint32_t flags, const LV2_Feature* const* features)
176 schoenebeck 2304 {
177     LV2_State_Map_Path* OldMapPath = MapPath;
178     LV2_State_Make_Path* OldMakePath = MakePath;
179     SetStateFeatures(features);
180    
181     if (MakePath && MapPath) {
182     char* abs_path = MakePath->path(MakePath->handle, "linuxsampler");
183     dmsg(2, ("saving to file %s\n", abs_path));
184    
185     std::ofstream out(abs_path);
186 capela 2174 out << GetState();
187 persson 1777
188 schoenebeck 2304 char* path = MapPath->abstract_path(MapPath->handle, abs_path);
189    
190 capela 2291 store(handle,
191 persson 2356 uri_to_id(NS_LS "state-file"),
192 capela 2291 path,
193     strlen(path) + 1,
194 persson 2356 uri_to_id(LV2_ATOM__Path),
195 capela 2291 LV2_STATE_IS_PORTABLE);
196 schoenebeck 2304
197     free(path);
198     free(abs_path);
199 capela 2174 } else {
200     dmsg(2, ("saving to string\n"));
201 persson 1777
202 capela 2174 std::ostringstream out;
203     out << GetState();
204    
205 capela 2291 store(handle,
206 persson 2356 uri_to_id(NS_LS "state-string"),
207 capela 2174 out.str().c_str(),
208     out.str().length() + 1,
209 persson 2356 uri_to_id(LV2_ATOM__String),
210 capela 2291 LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
211 capela 2174 }
212 persson 1777 dmsg(2, ("saving done\n"));
213 schoenebeck 2304
214     MapPath = OldMapPath;
215     MakePath = OldMakePath;
216 capela 2340
217     return LV2_STATE_SUCCESS;
218 persson 1777 }
219    
220 capela 2340 LV2_State_Status PluginLv2::Restore(
221 persson 2356 LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle,
222     uint32_t rflags, const LV2_Feature* const* features)
223 schoenebeck 2304 {
224     LV2_State_Map_Path* OldMapPath = MapPath;
225     LV2_State_Make_Path* OldMakePath = MakePath;
226     SetStateFeatures(features);
227    
228 capela 2174 size_t size;
229     uint32_t type;
230     uint32_t flags;
231    
232     const void* value = retrieve(
233 capela 2291 handle,
234 persson 2356 uri_to_id(NS_LS "state-file"),
235 capela 2174 &size, &type, &flags);
236     if (value) {
237 persson 2311 // Restore from state-file
238 persson 2356 assert(type == uri_to_id(LV2_ATOM__Path));
239 capela 2291 const String path((const char*)value);
240 capela 2174 dmsg(2, ("linuxsampler: restoring from file %s\n", path.c_str()));
241     std::ifstream in(path.c_str());
242     String state;
243     std::getline(in, state, '\0');
244     SetState(state);
245 persson 2311 } else if ((value = retrieve(handle,
246 persson 2356 uri_to_id(NS_LS "state-string"),
247 persson 2311 &size, &type, &flags))) {
248     // Restore from state-string
249 capela 2174 dmsg(2, ("linuxsampler: restoring from string\n"));
250 persson 2356 assert(type == uri_to_id(LV2_ATOM__String));
251 capela 2174 String state((const char*)value);
252     SetState(state);
253 persson 2311 } else {
254     // No valid state found, reset to default state
255     dmsg(2, ("linuxsampler: restoring default state\n"));
256     SetState(DefaultState);
257 capela 2174 }
258    
259 persson 2311 MapPath = OldMapPath;
260     MakePath = OldMakePath;
261 schoenebeck 2304
262 capela 2340 return LV2_STATE_SUCCESS;
263 persson 1777 }
264    
265     LV2_Handle instantiate(const LV2_Descriptor* descriptor,
266     double sample_rate, const char* bundle_path,
267     const LV2_Feature* const* features) {
268     return new PluginLv2(descriptor, sample_rate, bundle_path, features);
269     }
270    
271     void connect_port(LV2_Handle instance, uint32_t port, void* data_location) {
272     static_cast<PluginLv2*>(instance)->ConnectPort(port, data_location);
273     }
274    
275     void activate(LV2_Handle instance) {
276     static_cast<PluginLv2*>(instance)->Activate();
277     }
278    
279     void run(LV2_Handle instance, uint32_t sample_count) {
280     static_cast<PluginLv2*>(instance)->Run(sample_count);
281     }
282    
283     void deactivate(LV2_Handle instance) {
284     static_cast<PluginLv2*>(instance)->Deactivate();
285     }
286    
287     void cleanup(LV2_Handle instance) {
288     delete static_cast<PluginLv2*>(instance);
289     }
290    
291 capela 2340 LV2_State_Status save(LV2_Handle handle, LV2_State_Store_Function store,
292     LV2_State_Handle state,
293     uint32_t flags, const LV2_Feature* const* features) {
294 schoenebeck 2304 return static_cast<PluginLv2*>(handle)->Save(
295     store, state, flags, features);
296 persson 1777 }
297    
298 capela 2340 LV2_State_Status restore(LV2_Handle handle, LV2_State_Retrieve_Function retrieve,
299     LV2_State_Handle state,
300     uint32_t flags, const LV2_Feature* const* features) {
301 schoenebeck 2304 return static_cast<PluginLv2*>(handle)->Restore(
302     retrieve, state, flags, features);
303 persson 1777 }
304    
305     PluginInfo PluginInfo::Instance;
306    
307     PluginInfo::PluginInfo() {
308     Lv2.URI = "http://linuxsampler.org/plugins/linuxsampler";
309     Lv2.activate = activate;
310     Lv2.cleanup = cleanup;
311     Lv2.connect_port = connect_port;
312     Lv2.deactivate = deactivate;
313     Lv2.instantiate = instantiate;
314     Lv2.run = run;
315     Lv2.extension_data = extension_data;
316 capela 2291 StateInterface.save = save;
317     StateInterface.restore = restore;
318 persson 1777 }
319    
320    
321     const void* extension_data(const char* uri) {
322     dmsg(2, ("linuxsampler: extension_data %s\n", uri));
323 capela 2340 if (strcmp(uri, LV2_STATE__interface) == 0) {
324 capela 2291 return PluginInfo::Lv2StateInterface();
325 persson 1777 }
326     return 0;
327     }
328     }
329    
330    
331     extern "C" {
332     LV2_SYMBOL_EXPORT
333     const LV2_Descriptor* lv2_descriptor(uint32_t index) {
334     return index == 0 ? PluginInfo::Lv2Descriptor() : 0;
335     }
336     }

  ViewVC Help
Powered by ViewVC