
Just in case anyone is interested. I finally overcame those
difficulties and released HLADSPA 0.2 which can be found at
http://www.student.nada.kth.se/~alfonsoa/HLADSPA/HLADSPA-0.2.tgz
whose changelog is
2006-11-21 Version 0.2
* API refactored (now the plugins are coded in pure haskell98 + TH
and it doesnt depend on the latest (6.6) version of ghc anymore)
* Created proper Make system
(http://hackage.haskell.org/trac/ghc/ticket/933 + the use
of template records didn't allow it)
* Fixed lots of major and minor bugs
* Added Amp and (currently broken) ForSyDeEq plugins
On 11/5/06, Alfonso Acosta
The essential code snippet is,
===================== -- Existentially quantified records allow the plugin developer -- to chose hd and id types at will and, allowing to declare "heterogeneous" -- Descriptor lists. Drawback: it only works in ghc 6.6 and -- makes the design tricky. The problem comes from modelling (void*) in Haskell
-- id is the implementation data data Descriptor = forall id. Descriptor {uniqueID :: LadspaIndex, label :: String, properties :: LadspaProperties, name, maker, copyright :: String, portCount :: LadspaIndex, portDescriptors :: [PortDescriptor], portNames :: [String], portRangeHints :: [PortRangeHint], _implementationData :: id, _instantiate :: Descriptor -> LadspaIndex -> Maybe Instance}
-- hd is the handle data Instance = forall hd. Instance { _this :: hd, -- initial handle -- In this case we are using lists to represent the port I/O buffers, so the -- port connections (buffer pointers of ports) is handled by the marshaller -- connectPort :: (hd -> LadspaIndex -> Ptr LadspaData -> IO hd) _activate :: Maybe(hd -> IO ()), -- (LadspaIndex,PortData) indicates the portnumber and its data _run :: hd -> LadspaIndex -> [(LadspaIndex,PortData)] -> ([(LadspaIndex,PortData)], hd), -- Not yet implemented (is not mandatory for a plugin to provide them) -- _runAdding :: -- _setAddingGain :: _deactivate :: Maybe (hd -> IO ()), _cleanup :: hd -> IO () } =====================
This is the best solution I could come up with and I'm not still happy with it. The trickiest part, was modelling (void*) in Haskell.
I know that using lists for I/O buffers is inefficient but I coded it having ForSyDe in mind. If people show interest I can code a faster StorableArray-version.
Here are my questions.
* I'm using GHC's existentially quantified records extension to hide the hd and id parameters because the plugin programmer has to be able to provide a collection of Descriptor (a Descriptor list in current release). I would love to find a solution in plain Haskell98. Any ideas?
* This approach requires splitting the original C LADSPA_Descriptor struct in the Descriptor and Instance Haskell types, which leads to a design error: there are functions (e.g. _run, _activate ... ) in Instance which really belong to Descriptor (those functions shouldn't change with the plugin instance). For example, with this approach, it is not possible to tell the plugin host if activate() or deactivate() will be used because this is "asked" any instances is created.
* Real Time support in HLADSPA. From LADSPA's documentation:
"Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin is capable of running not only in a conventional host but also in a `hard real-time' environment. To qualify for this the plugin must satisfy all of the following: (1) The plugin must not use malloc(), free() or other heap memory management within its run() or run_adding() functions. All new memory used in run() must be managed via the stack. These restrictions only apply to the run() function."
Should I forget about HARD_RT_CAPABLE with Haskell? Is there a way to control the use of the heap by a function?
* I'm not so sure about the types of _activate, _deactivate and _cleanup. I don't even know if I should include them because they only seem to be required by a language with side effects. Furthermore, _activate() and _deactivate() don't seem to have sense with current implementation cause they are "separated from instantiate() to aid real-time support" and using lists as I/O buffers discards RT support (see above)
Thanks in advance for your comments/answers,
Alfonso Acosta