|
05-30-2016, 06:37 AM
|
#1
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
IMidiQueue - How to clone it?
Hi there,
I'm creating a IMidiQueue with N notes. Once created, I process it (peak and remove) inside PDR during the time.
Once its empty, I'd like to just reuse it, without "recreating" it every time: so, without creating and add the N notes again (which for my purpose will be identical).
How can I basically "clone" it?
Last edited by Nowhk; 05-30-2016 at 06:46 AM.
|
|
|
05-30-2016, 11:28 PM
|
#2
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
I'm not sure if I understand... Do you want to get to the notes in the queue without removing them?
|
|
|
05-31-2016, 12:04 AM
|
#3
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
I'm not sure if I understand... Do you want to get to the notes in the queue without removing them?
|
Hi Tale Thanks for the reply.
Well, basically I've made a sequencer that play notes and loop at some points.
So I create notes and I add them to a IMidiQueue, which will sort due to the offset. Within the PDR, I check the first "incoming" notes with a while (basic MIDI processing), or I break the process:
Code:
while (!queuedNotes.Empty()) {
IMidiMsg* note = queuedNotes.Peek();
if (note->mOffset > myOffset) break;
SendMidiMsg(note);
queuedNotes.Remove();
}
The problem is that once I finish the note and I loop the pattern, I need to re-process the same midi notes (which I've removed).
I'd like to avoid re-creating them at PDR (since could take lots of resources), and just wrap or clone the IMidiQueue.
Is it more clear now?
|
|
|
05-31-2016, 12:50 AM
|
#4
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Yeah, got it, thanks. It never occurred to me to use IMidiQueue for a sequencer, that's smart.
Anyway, I guess you could do something like:
Code:
if (!queuedNotes.Empty())
{
for (;;)
{
IMidiMsg* note = queuedNotes.Peek(mSeqIndex);
if (note->mOffset - mSeqOffset > myOffset) break;
SendMidiMsg(note);
if (++mSeqIndex >= queuedNotes.ToDo())
{
mSeqIndex = mSeqOffset = 0;
}
}
mSeqOffset += myOffset;
}
You would have to init mSeqIndex(0) and mSeqOffset(0), and you need to add Peek(int) to IMidiQueue:
Code:
inline IMidiMsg* Peek(int index) const
{
return &mBuf[mFront + index];
}
|
|
|
05-31-2016, 01:04 AM
|
#5
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
Yeah, got it, thanks. It never occurred to me to use IMidiQueue for a sequencer, that's smart.
Anyway, I guess you could do something like:
Code:
if (!queuedNotes.Empty())
{
for (;;)
{
IMidiMsg* note = queuedNotes.Peek(mSeqIndex);
if (note->mOffset - mSeqOffset > myOffset) break;
SendMidiMsg(note);
if (++mSeqIndex >= queuedNotes.ToDo())
{
mSeqIndex = mSeqOffset = 0;
}
}
mSeqOffset += myOffset;
}
You would have to init mSeqIndex(0) and mSeqOffset(0), and you need to add Peek(int) to IMidiQueue:
Code:
inline IMidiMsg* Peek(int index) const
{
return &mBuf[mFront + index];
}
|
I see. Thanks. But for my code this will mess a bit the whole mechanism. What about this instead:
I send midi
I change offset adding the lenght of the pattern
I add the note to the queue (thus, at the end of the queue)
I call remove
In this way, I wrap the notes (adding them) at the end, with the right offset. Would this so expensive? I call "Flush" (so Compact) when looping. This will free the old and no more used memory...
|
|
|
05-31-2016, 06:54 AM
|
#6
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Nowhk
In this way, I wrap the notes (adding them) at the end, with the right offset. Would this so expensive? I call "Flush" (so Compact) when looping. This will free the old and no more used memory...
|
IMidiQueue is really light-weight (e.g. remove just updated an index), so I would not expect any problems, even if you do fill it again every process call. I would make sure you use it as a member variable, that way it only initially allocates some memory, and never frees it again until your plug-in is destructed.
|
|
|
05-31-2016, 10:09 AM
|
#7
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
IMidiQueue is really light-weight (e.g. remove just updated an index), so I would not expect any problems, even if you do fill it again every process call.
|
I know. I only free (flush) the memory one time per loop. But I add a note every time I process another one. Add "copy" the whole element and put it at the end, but it also seems to be a light task.
If I use a std::vector for example, and I create new One (deleting the previous) it glitch the whole process. It seems to be a lot heavy than your queue.
Do you agree that those kind of containers should be avoid working with audio?
|
|
|
06-01-2016, 03:09 AM
|
#8
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Nowhk
I know. I only free (flush) the memory one time per loop. But I add a note every time I process another one. Add "copy" the whole element and put it at the end, but it also seems to be a light task.
|
FYI: Flush doesn't actually free memory, but it does move the MIDI messages still in the queue.
Quote:
Originally Posted by Nowhk
If I use a std::vector for example, and I create new One (deleting the previous) it glitch the whole process. It seems to be a lot heavy than your queue.
Do you agree that those kind of containers should be avoid working with audio?
|
Yeah, I agree. Then again, I am not very fond of STL in general anyway, so I try to avoid them anyway...
|
|
|
06-01-2016, 03:13 AM
|
#9
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
FYI: Flush doesn't actually free memory, but it does move the MIDI messages still in the queue.
|
Really? I see this:
Code:
// Removes a MIDI message from the front of the queue (but does *not*
// free up its space until Compact() is called).
inline void Remove() { ++mFront; }
and inside Flush there's Compact(). So in fact I'm filling memory (uselessly) at each "Add" (since Remove doesn't free it up)? Wouldn't it better (working with audio) free up memory once I remove a note?
|
|
|
06-01-2016, 03:21 AM
|
#10
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Well, it does move MIDI messages to the front of the queue (thus freeing up space at the end of the queue), but it doesn't call free().
Last edited by Tale; 06-02-2016 at 04:32 AM.
|
|
|
06-02-2016, 12:27 AM
|
#11
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
Well, it does move MIDI messages to the front of the queue (thus freeing up space at the end of the queue), but it does call free().
|
Does or doesnt? Typo?
|
|
|
06-02-2016, 04:32 AM
|
#12
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Nowhk
Does or doesnt? Typo?
|
Doesn't, oops! I will edit my post...
|
|
|
06-02-2016, 10:29 AM
|
#13
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
Doesn't, oops! I will edit my post...
|
So, every time I add a note it makes a copy of the IMidiMsg, but never destroy it ? After 1000 note Add and 900 remove I still have allocated 1000 objects without removing any of them :O Is it good for an audio application?
|
|
|
06-02-2016, 11:34 AM
|
#14
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Usually you allocate memory during construction, or in Reset() by calling mMidiQueue.Resize(GetBlockSize()). This memory will indeed not be freed again until your plug-in is closed. This is good for audio, because (re)allocating during processing could results in pops/clicks.
|
|
|
06-03-2016, 06:32 AM
|
#15
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
Usually you allocate memory during construction, or in Reset() by calling mMidiQueue.Resize(GetBlockSize()). This memory will indeed not be freed again until your plug-in is closed. This is good for audio, because (re)allocating during processing could results in pops/clicks.
|
I see. Thanks for all infos
Where do you allocate memory in ctor for IMidiQueue? I see the Expand() method, which should serve the cause (using realloc method). But before call it, you set mSize to 0, so size is 0/something = 0, which seems to allocate nothing :O I miss a point...
Last edited by Nowhk; 06-03-2016 at 06:45 AM.
|
|
|
06-03-2016, 02:35 PM
|
#16
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
The idea is that you either call mMidiQueue.Resize(expected_max) in your constructor, and/or in Reset() if you want expected_max to be block size dependent. That way malloc() is only called before processing any audio, assuming that the queue will never grow beyond expected_max. If it does grow beyond that at some point, then Expand() will realloc() during audio processing.
|
|
|
06-05-2016, 10:35 AM
|
#17
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
The idea is that you either call mMidiQueue.Resize(expected_max) in your constructor, and/or in Reset() if you want expected_max to be block size dependent. That way malloc() is only called before processing any audio, assuming that the queue will never grow beyond expected_max. If it does grow beyond that at some point, then Expand() will realloc() during audio processing.
|
Never call resize on my class. So basically what Ive do till now is to create a IMidiQueue of 1 and expand it every time I add a new note? I thought it is already allocated with DEFAUL_BLOCK_SIZE, but in fact default (init) size is 1.
Edit: oh no wait, its already allocated with DEFAULT_BLOCK_SIZE: theres * mGrow within Expand, didnt see it.
Last edited by Nowhk; 06-05-2016 at 10:41 AM.
|
|
|
06-05-2016, 10:48 AM
|
#18
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Yeah... Note that if you don't explicitly call Resize(), then the very first call Add() will allocate memory. I guess you are calling Add() from within the audio thread, and during processing? Then it probably would be better to call Resize() during plug-in construction, or in your plug-in's Reset().
|
|
|
06-05-2016, 11:20 AM
|
#19
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
Yeah... Note that if you don't explicitly call Resize(), then the very first call Add() will allocate memory.
|
Really? I see Expand (called in the CTOR) use realloc, so it should already allocate memory there... no?
|
|
|
06-05-2016, 01:09 PM
|
#20
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Nowhk
Really? I see Expand (called in the CTOR) use realloc, so it should already allocate memory there... no?
|
Yes, you are right of course (doh!). Hey, I just write this stuff, I don't really know how it works...
|
|
|
06-06-2016, 06:39 AM
|
#21
|
Human being with feelings
Join Date: Mar 2016
Posts: 234
|
Quote:
Originally Posted by Tale
Yes, you are right of course (doh!). Hey, I just write this stuff, I don't really know how it works...
|
No problem. So I'm ok, it already allocate 1024 IMidiMsg when I declare it. I think I'm good this way, since I'll use/wrap max 10 notes. Even if I do 8000 Add() (followed by parallel Remove) it will always use this memory without grows more. Great! Thanks dude!
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 04:56 PM.
|