RFC and Announcement: HLADSPA, LADSPA for Haskell

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

RFC and Announcement: HLADSPA, LADSPA for Haskell

Bugzilla from alfonso.acosta@gmail.com
Hi all,

Let me introduce myself. I'm a computer science engineering student,
writing his masters thesis about a VHDL translator for ForSyDe
(http://www.imit.kth.se/info/FOFU/ForSyDe/ , a Hardware Description
Language embedded in Haskell)

In order to show a practical application of ForSyDe I decided to try
with its audio processing design capabilities. For that purpouse I
decided to port LADSPA (http://www.ladspa.org/ ) to Haskell.

The result so far is HLADSPA 0.1, which can be downloaded from
http://www.student.nada.kth.se/~alfonsoa/HLADSPA-0.1.tgz and contains
a testing plugin (Null.hs).

It requires GHC>=6.6 due to the use of template haskell and
existentially quantified records (read on for more on this).

Even for people not interested in LADSPA itself, the project can be
regarded as an example of how to create plugins and shared libraries
in Haskell without making use hs-plugins.

I'll be happy to read any comments and/or questions regarding the
project. Here are the design questions on my side:

The most important part for creating the HLADSPA, was modelling the
LADSPA header file (http://www.ladspa.org/ladspa_sdk/ladspa.h.txt ) in
Haskell (http://www.student.nada.kth.se/~alfonsoa/HLADSPA-0.1/HLADSPA.hs
)

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


PS1: Big thanks and claps for the people at #haskell@Freenode . They
helped a lot to make this initial release possible.
PS2: I would like to get the project hosted at the darcs repository at
haskell.org. Do you consider it interesting enough for it?
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: RFC and Announcement: HLADSPA, LADSPA for Haskell

Bugzilla from alfonso.acosta@gmail.com
On 11/5/06, Alfonso Acosta <[hidden email]> wrote:

> * 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.

I meant "because this is 'asked' _before_ any instances are created", sorry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: RFC and Announcement: HLADSPA, LADSPA for Haskell

Henning Thielemann
In reply to this post by Bugzilla from alfonso.acosta@gmail.com

On Sun, 5 Nov 2006, Alfonso Acosta wrote:

> PS1: Big thanks and claps for the people at #haskell@Freenode . They
> helped a lot to make this initial release possible.
> PS2: I would like to get the project hosted at the darcs repository at
> haskell.org. Do you consider it interesting enough for it?

Yes, definitely. Could you also please add some note to
  http://www.haskell.org/haskellwiki/Libraries_and_tools/Music_and_sound
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: RFC and Announcement: HLADSPA, LADSPA for Haskell

Donald Bruce Stewart
lemming:

>
> On Sun, 5 Nov 2006, Alfonso Acosta wrote:
>
> > PS1: Big thanks and claps for the people at #haskell@Freenode . They
> > helped a lot to make this initial release possible.
> > PS2: I would like to get the project hosted at the darcs repository at
> > haskell.org. Do you consider it interesting enough for it?
>
> Yes, definitely. Could you also please add some note to
>   http://www.haskell.org/haskellwiki/Libraries_and_tools/Music_and_sound

I agree, and would remark for anyone reading:

Please add your projects, whether they are applications, libraries,
tools, darcs repos, to :

    http://haskell.org/haskellwiki/Libraries_and_tools

*All* Haskell code that's available, and fit to compile should be
findable from that page.

-- Don
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: RFC and Announcement: HLADSPA, LADSPA for Haskell

Bugzilla from alfonso.acosta@gmail.com
In reply to this post by Henning Thielemann
> > PS2: I would like to get the project hosted at the darcs repository at
> > haskell.org. Do you consider it interesting enough for it?
>
> Yes, definitely. Could you also please add some note to
>   http://www.haskell.org/haskellwiki/Libraries_and_tools/Music_and_sound

That's something I had in mind from the very beginning, but I didn't
want to add anything to the Libraries section before deciding upon
where I was going to host it.

As suggested at
http://haskell.org/haskellwiki/How_to_write_a_Haskell_program#Hosting
I'll contact Simon Marlow to ask for it.

Can anyone confirm if wrting to simonmar _at_ microsoft _dot_ com is
the right way to reach him for his purpose? (I couldn't find any
haskell.org-specific address)
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: RFC and Announcement: HLADSPA, LADSPA for Haskell

Bugzilla from alfonso.acosta@gmail.com
In reply to this post by Bugzilla from alfonso.acosta@gmail.com
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 <[hidden email]> wrote:

> 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
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe