Copy clips

Hi,

is there a convenient approach to copy clips? I have tried to use the seletionManager::copy and paste. But it doesn’t seem to work. It only throws the known: JUCE Assertion failure in tracktion_SelectionManager.cpp:255 but nothing happens.

The assertion is telling you that you haven’t registered a SelectableClass for the type of object you’re trying to select. The SelectableClass interface is a fairly high level class designed to perform operations on groups of objects and defines logic for selecting different types of object (for example, if you have a MIDI clip selected, and you add an audio clip to the selection, there might be a common set of properties you can expose but not all the properties of an audio and MIDI clip. Similarly, you probably won’t want to be able to select a Track and Clip at the same time).

So you can implement SelectableClasses for all your objects if you want to, but you might simply get away with using the Clipboard class itself. You can add content of various types and then paste it in to an Edit.

Does that help?

2 Likes

Hi, Dave. Thank you for your help. I don’t really get how to use the Clipboard Class. Do I have to derive from it?

No, it is a singleton so you can just call Clipboard::getInstance().

You then add content to the clipboard e.g.

auto clipContent = std::make_unique<Clipboard::Clips>();
clipContent->addClip (trackOffset, clip->getState());
Clipboard::getInstance()->setContent (std::move (clipContent));

Then elsewhere you can paste that in to an Edit:

Clipboard::getInstance()->pasteIntoEdit (Clipboard::ContentType::EditPastingOptions (edit, editInsertPoint));

Does that cover what you need?

1 Like

Thank you so much! I will give it a try.

It works! Thank you! :star_struck:

Will a similar technique to this work for copy/paste of midi notes?

What would that look like?

            auto content = std::make_unique<Clipboard::MIDINotes>();

            for (auto* mn : events->getSelectedNotes())
            {
                jassert (mn->state.isValid());
                content->notes.emplace_back (mn->state.createCopy());
            }

            params.clipboard.setContent (std::move (content));

Thank you! …very helpful.

I have tried some copy/paste code that I fear is naïve. It works mostly, but has some strangeness, mostly when pasting to another track.

Copy code;

	auto clipContent = std::make_unique<te::Clipboard::Clips>();
	clipContent->addClip(0, clipPtr->state);
	te::Clipboard::getInstance()->setContent(std::move(clipContent));
	clipStartPosition = clipPtr->getPosition().getStart();

Paste code;

	const auto position{ clipPtr->edit.getTransport().getCurrentPosition() };
	te::EditInsertPoint insertPoint{ clipPtr->edit };
	insertPoint.setNextInsertPoint(position - clipStartPosition);
	te::Clipboard::getInstance()->getContent()->pasteIntoEdit(clipPtr->edit, insertPoint, &editViewState.selectionManager);

Any suggestions are welcome?

What type of strangeness?

Yes, apologies for being a bit vague.

If I paste to the same track, it works as expected.

But, when I paste to a different track, the clip does not appear at the playhead position. It has some kind of offset.

Hmmm…found more strangeness.

If I paste to the same track, but earlier in the timeline, it does not paste at the playhead position!

So, as long as I paste after the copied clip, it works as expected. But not if the paste is earlier, or on another track.

Obviously, I have missed something.

I am using a slightly different method of copying and pasting than you are and mine works as expected even when pasting to a different track:

copy

 tracktion_engine::Clipboard::getInstance()->clear();
auto clipContent = std::make_unique<tracktion_engine::Clipboard::Clips>();
clipContent->addClip(0, clip->state);
tracktion_engine::Clipboard::getInstance()->setContent(std::move(clipContent));

paste

 auto clipboard = tracktion_engine::Clipboard::getInstance();
            if (!clipboard->isEmpty())
            {

                if (clipboard->hasContentWithType<tracktion_engine::Clipboard::Clips>())
                {

                    auto clipContent = clipboard->getContentWithType<tracktion_engine::Clipboard::Clips>();
                    tracktion_engine::EditInsertPoint insertPoint(edit);
                    insertPoint.setNextInsertPoint(edit.getTransport().getCurrentPosition(), track);

                    tracktion_engine::Clipboard::ContentType::EditPastingOptions options(edit, insertPoint);

                    double start = 0;
                    for (auto& i : clipContent->clips)
                    {
                        auto end = i.hasBeatTimes ? edit.tempoSequence.beatsToTime(i.startBeats)
                                                  : (static_cast<double>(i.state.getProperty (tracktion_engine::IDs::start)));

                        start = std::max (start, end);
                    }

                    options.startTime = edit.getTransport().getCurrentPosition() - start;
                    clipContent->pasteIntoEdit(options);


                }

            }

I initially was having offset issues as well, I took some of the code from the pasteIntoEditAtCursor or whatever that method was called and used that to compute that clip start time and get rid of the offset. I only ever copy one clip at a time though. The loop probably isnt needed but I basically just copied it from that one method I mentioned and changed a few things and it finally worked. Had a really hard time lol.

Thank you!

Your method works for me also!

I will probably remove the loop as you mentioned. But it works for pasting on the same or a different track. And also if pasting earlier in the timeline.

Many kudos for sharing!

Glad I could help!

Below is my version of @denvercoder9’s code.

I have removed the loop.
Copy;

    te::Clipboard::getInstance()->clear();
    auto clipContent = std::make_unique<te::Clipboard::Clips>();
    clipContent->addClip(0, clipPtr->state);
    te::Clipboard::getInstance()->setContent(std::move(clipContent));

Paste;

    auto clipContent = clipboard->getContentWithType<te::Clipboard::Clips>();
    te::EditInsertPoint insertPoint(clipPtr->edit);
    insertPoint.setNextInsertPoint(clipPtr->edit.getTransport().getCurrentPosition(), clipPtr->getTrack());

    te::Clipboard::ContentType::EditPastingOptions options(clipPtr->edit, insertPoint);

    auto& clip{ clipContent->clips[0] };

    const auto start = static_cast<double>(clip.state.getProperty(te::IDs::start));

    options.startTime = (clipPtr->edit.getTransport().getCurrentPosition() - start);						 
    clipContent->pasteIntoEdit(options);

Thanks again!

3 Likes

I have the copy midi notes to clipboard working, but the paste from the clipboard into a clip is giving me problems.

Can you share an example of the “paste” version of this code?

Specifically, with the code below as the “copy”,

te::Clipboard::getInstance()->clear();
for (auto midiNote : midiList.getNotes())
	midiContent->notes.emplace_back(midiNote->state.createCopy());
te::Clipboard::getInstance()->setContent(std::move(midiContent));

What would be the matching “paste” code?

auto clipboard{ te::Clipboard::getInstance() };
// now make sure we have midi notes
if (auto clipContent{ clipboard->getContentWithType<te::Clipboard::MIDINotes>() })
{
	// code to insert midi into clip
}

The simplest way would be this I think to paste in to an existing clip:

if (auto midiNotes = Clipboard::getInstance()->getContentWithType<Clipboard::MIDINotes>())
{
    auto notesAdded = midiNotes->pasteIntoClip (*midiClip, {}, transportControl.position, snap);
    //...
}