lv2_atom_forge_resource vs lv2_atom_forge_object

Programming applications for making music on Linux.

Moderators: MattKingUSA, khz

Post Reply
User avatar
peter.semiletov
Established Member
Posts: 118
Joined: Thu May 11, 2023 1:09 pm
Has thanked: 25 times
Been thanked: 80 times
Contact:

lv2_atom_forge_resource vs lv2_atom_forge_object

Post by peter.semiletov »

Hello! I'm completely stucked with LV2 documentiation and the difference between lv2_atom_forge_resource and lv2_atom_forge_object. I'm trying to remove the deprecated lv2_atom_forge_resource from DrMr fork. The documentation suggests that lv2_atom_forge_resource is "The same as lv2_atom_forge_object(), but for object:Resource. This function is deprecated and should not be used in new code. Use lv2_atom_forge_object() directly instead."
But what that means, how is that - "directly"? For example, here are the working code:

Code: Select all

  LV2_Atom_Forge_Frame set_frame;
  uint8_t msg_buf[1024];
  lv2_atom_forge_set_buffer (&ui->forge, msg_buf, 1024);
  LV2_Atom *msg = (LV2_Atom*)lv2_atom_forge_resource (&ui->forge, &set_frame, 1, ui->uris.ui_msg);
  (*add_data)(ui, data);
  lv2_atom_forge_pop (&ui->forge, &set_frame);
  ui->write (ui->controller, DRUMROX_CONTROL, lv2_atom_total_size(msg), ui->uris.atom_eventTransfer, msg);

If I change lv2_atom_forge_resource to lv2_atom_forge_object, it won't work. What is the difference, what is the object here - forge, set_frame?

tramp
Established Member
Posts: 2335
Joined: Mon Jul 01, 2013 8:13 am
Has thanked: 9 times
Been thanked: 454 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by tramp »

here is a working example for lv2_atom_forge_object(), transfer audio data from dsp to UI:
https://github.com/brummer10/XWaveView. ... w.cpp#L114

On the road again.
User avatar
peter.semiletov
Established Member
Posts: 118
Joined: Thu May 11, 2023 1:09 pm
Has thanked: 25 times
Been thanked: 80 times
Contact:

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by peter.semiletov »

Thank you! But it does not give me the understanding :( "I think I'm dumb" (c)Nirvana
I found the source of both functions:

Code: Select all

static inline LV2_Atom_Forge_Ref
lv2_atom_forge_resource(LV2_Atom_Forge*       forge,
                        LV2_Atom_Forge_Frame* frame,
                        LV2_URID              id,
                        LV2_URID              otype)
{
	const LV2_Atom_Object a = {
		{ sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Resource },
		{ id, otype }
	};
	LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
	return lv2_atom_forge_push(forge, frame, out);
}

And:

Code: Select all

static inline LV2_Atom_Forge_Ref
 lv2_atom_forge_object(LV2_Atom_Forge*       forge,
                       LV2_Atom_Forge_Frame* frame,
                       LV2_URID              id,
                       LV2_URID              otype)
 {
     const LV2_Atom_Object a = {
         { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object },
         { id, otype }
     };
     return lv2_atom_forge_push(
         forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
 }

They are seem very similar except the first one uses forge->Resource, and the last uses forge->Object. I cannot understand

tramp
Established Member
Posts: 2335
Joined: Mon Jul 01, 2013 8:13 am
Has thanked: 9 times
Been thanked: 454 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by tramp »

You must see it in conjunction with the read function. On the one side you forge a object, set a key and then add a value. In the read function you check if it is a object, check which key it is and then read the value and know for what it is.
here is the read function for the write function I posted above:
https://github.com/brummer10/XWaveView. ... _ui.c#L290

On the road again.
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 357 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by j_e_f_f_g »

I hate that forge crap. All is does is a very complicated copying of data to a buffer. The source code is incredibly inefficient, allocates memory (without your plugin being aware that's what the code is doing) without checking its validity, and isn't properly documented. I threw all that stuff away once I figured out what it was doing, and instead wrote my own buffer formatting routines (properly commented). I can call them from my run() function, because they don't allocate memory. And they're more efficient, for example looking up URIDs once only, instead of each time some forge...() is instantiated.

The forge source code also hides some very important details which aren't documented anywhere else, like how messages copied to the buffer need to be padded out to 8 byte boundaries. And that isn't reflected in the message's size field.

LV2 is a huge mess. I recommend that, if you're just starting out writing a plugin, go with either vst3 or clap.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

User avatar
peter.semiletov
Established Member
Posts: 118
Joined: Thu May 11, 2023 1:09 pm
Has thanked: 25 times
Been thanked: 80 times
Contact:

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by peter.semiletov »

tramp wrote: Sun Jun 04, 2023 4:45 pm

You must see it in conjunction with the read function. On the one side you forge a object, set a key and then add a value. In the read function you check if it is a object, check which key it is and then read the value and know for what it is.
here is the read function for the write function I posted above:
https://github.com/brummer10/XWaveView. ... _ui.c#L290

Thank you a lot!!! Now I get all works as intended!

User avatar
peter.semiletov
Established Member
Posts: 118
Joined: Thu May 11, 2023 1:09 pm
Has thanked: 25 times
Been thanked: 80 times
Contact:

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by peter.semiletov »

j_e_f_f_g wrote: Sun Jun 04, 2023 5:12 pm

LV2 is a huge mess. I recommend that, if you're just starting out writing a plugin, go with either vst3 or clap.

I'm trying to make something with DrMr fork - Drumrox (https://github.com/psemiletov/drumrox). It was C/LV2/GTK2. I've started to rewrite parts of the code to C++, and want to move from GTK2 some later to make Drumrox compatible with Reaper.
Currenly I rewrote the internal mixer part (panning laws were added) and drumkit loader. I was afraid of LV2, but I need the good drum machine with Hydrogen kits support, so I am doomed to develop Drumrox further :)

sjaehn
Established Member
Posts: 138
Joined: Fri May 03, 2019 6:05 pm
Has thanked: 29 times
Been thanked: 61 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by sjaehn »

j_e_f_f_g wrote: Sun Jun 04, 2023 5:12 pm

The source code is incredibly inefficient, allocates memory (without your plugin being aware that's what the code is doing) without checking its validity, and isn't properly documented.

Where exactly is memory allocated in lv2 atom forge? It's the turn to the plugin programmer to provide memory. This is the way how it should work. Or did I miss something?

No, there is NO dynamic memory allocation in lv2 atom forge (lv2_atom_forge_init() may indirectly allocate memory depending on the host-provided map function, but this is not a problem as it should be called once outside the realtime methods anyway). No (m/c)alloc(), no free(). And nothing else. Just take a look into https://github.com/lv2/lv2/blob/master/ ... om/forge.h. There are also two statements in the comments on the top of forge.h for everybody who doesn't want to take a closer look into the code:

This file provides an API for constructing Atoms which makes it relatively
simple to build nested atoms of arbitrary complexity without requiring
dynamic memory allocation.

and

This entire API is realtime safe if used with a buffer or a realtime safe
sink, except lv2_atom_forge_init() which is only realtime safe if the URI
map function is.

sjaehn
Established Member
Posts: 138
Joined: Fri May 03, 2019 6:05 pm
Has thanked: 29 times
Been thanked: 61 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by sjaehn »

Thanks to @tramp it seems to work now.

But @peter.semiletov I saw you asking in your code at https://github.com/psemiletov/drumrox/b ... x.cpp#L323:

Code: Select all

 lv2_atom_forge_write (&drumrox->forge, data, 3); //what is 3?

Three bytes for MIDI messages, see also https://github.com/lv2/lv2/blob/master/ ... #L304-L306

Code: Select all

/** Write raw output, padding to 64-bits as necessary. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)

Note: The data are stored in 8 byte blocks ("pad"). The remain 5 bytes are filled with 0. Nothing to worry about.

User avatar
peter.semiletov
Established Member
Posts: 118
Joined: Thu May 11, 2023 1:09 pm
Has thanked: 25 times
Been thanked: 80 times
Contact:

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by peter.semiletov »

Tnank you for the information! This part of DrMr source became clear for me.

User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by sadko4u »

sjaehn wrote: Mon Jun 05, 2023 10:46 am

No, there is NO dynamic memory allocation in lv2 atom forge (lv2_atom_forge_init() may indirectly allocate memory depending on the host-provided map function, but this is not a problem as it should be called once outside the realtime methods anyway). No (m/c)alloc(), no free(). And nothing else. Just take a look into https://github.com/lv2/lv2/blob/master/ ... om/forge.h. There are also two statements in the comments on the top of forge.h for everybody who doesn't want to take a closer look into the code:

You're right. There is no memory allocation inside of standard forge functions.
But if you provide your own functions for:

Code: Select all

  LV2_Atom_Forge_Sink        sink;
  LV2_Atom_Forge_Deref_Func  deref;
  LV2_Atom_Forge_Sink_Handle handle;

You actually can get a variable-sized forge buffer but you will lose the RT compatibility because of memory re-allocations which provide variable-size compatibility.

LV2:Atom fomat is also very easy transformable into Turtle format and back (as it is done in lilv). But it's not portable between LittleEndian and BigEndian platforms. I mean, if you generate LV2:Atom message on LittleEndian, you need to deal with byte ordering on the BigEndian machine when you receive it.

The main problem with standard LV2:Atom objects is that their structure is not well-defined in the documentation. So you'll probably won't generate a proper Patch:Get or Patch:Set message from the first take without dumping the proper one from some other solution.

LSP (Linux Studio Plugins) Developer and Maintainer.
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by sadko4u »

j_e_f_f_g wrote: Sun Jun 04, 2023 5:12 pm

I hate that forge crap. All is does is a very complicated copying of data to a buffer. The source code is incredibly inefficient, allocates memory (without your plugin being aware that's what the code is doing) without checking its validity, and isn't properly documented. I threw all that stuff away once I figured out what it was doing, and instead wrote my own buffer formatting routines (properly commented). I can call them from my run() function, because they don't allocate memory. And they're more efficient, for example looking up URIDs once only, instead of each time some forge...() is instantiated.

Maybe you did it wrong. The forge object should be instantiated and initialized at the same time the plugin becomes instantiated. And only at this moment it may be non-RT-safe. In all available examples I've seen this is done in such way.

LSP (Linux Studio Plugins) Developer and Maintainer.
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 357 times

Re: lv2_atom_forge_resource vs lv2_atom_forge_object

Post by j_e_f_f_g »

I just took a look at the lv2 site's forge.h, and this is significantly different than the one I looked at (years ago). First of all, there was no inline code. The .h contained only the definitions, and a separate forge.c file contained all the C code. There were no deprecated functions. I don't even remember a lv2_atom_forge_object. Plus, this contained functions to take a URID, and convert it to a path or string atom, and it was in those functions that the memory allocation was done.

Maybe it was an earlier version.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

Post Reply