RomeoDespres / reapy

A pythonic wrapper for REAPER's ReaScript Python API
MIT License
107 stars 25 forks source link

Question - how would I add a media item from Python using Reapy? #110

Open DrewTNBD opened 3 years ago

DrewTNBD commented 3 years ago

Sorry, couldn't think where else to ask really. Seems here would be the best place.

I've currently got a script that will build a Reaper project from a directory of audio files, and put those audio files on a set of tracks according to their names.

But I was wondering if it would be possible to have Reapy insert an audio file into a project and if so, how? Would I have to use the AudioAccessor?

The API doesn't specify an equivalent call for InsertMedia(const char* file, int mode)

Levitanus commented 3 years ago

Last time I've done this this way:

    def make_copy(
        self,
        position: float,
        length: ty.Optional[float] = None,
        additional_source_offset: float = 0.0,
    ) -> 'ItemsHandler':
        """Make copy of items and place them at position.

        Parameters
        ----------
        position : float
        length : Optional[float]
        additional_source_offset : float, optional
            If not 0.0 — source is shifted for each active take of each item
        """
        if not self.are_bounds_identical:
            raise ItemsError('bounds of items are not identical')
        new_i_hndlrs: ty.List[ItemHandler] = []
        for ih in self.item_handlers:
            old_item = ih.item
            old_take = old_item.active_take
            length = old_item.length if length is None else length
            new_item = old_item.track.add_item(start=position, length=length)
            new_item.set_info_value("D_VOL", old_item.get_info_value("D_VOL"))
            new_take = new_item.add_take()
            new_take.set_info_value("D_VOL", old_take.get_info_value("D_VOL"))
            new_take.source = old_take.source
            new_take.start_offset = (
                old_take.start_offset + additional_source_offset
            )
            new_i_hndlrs.append(ItemHandler(sr=self.sr, item=new_item))
        return ItemsHandler(sr=self.sr, item_handlers=new_i_hndlrs)

https://github.com/Levitanus/sample_editor/blob/b0be959538be24f0d791222879793915f5294405/sample_editor/item_handler.py#L236

makingpippop commented 3 years ago

I've added project.import_media() in my fork

The method returns the imported item so you could retrieve the newly created track with imported_item.track

Then you could do something like this, or even link your folder directly instead of using a list

from pathlib import Path

myFiles = ['./myFileA.wav', './myFileB.wav', './myFileC.wav']
project = reapy.Project()
for f in myFiles:
    f_path = Path(f)
    new_item = project.import_media(f)
    new_track = new_item.track
    #name of the file without extension
    new_track.name = f_path.stem

Hope this helps!

d-vyd commented 2 years ago

Hi @RomeoDespres & @makingpippop ,

Do either of you know how one might go about adding a track template to a project via reapy? I use Reaktor a lot and track templates permit adding the VST with a specific ensemble (patch) already loaded inside. Without such a template, there is no way to get Reaktor to load an ensemble programmatically. @makingpippop, I installed your fork for access to project.import_media, which works great on MIDI files. But, when I supplied the path to a track template, I received an error:

Traceback (most recent call last):
  File "d:/Documents/Programming/python/reaper/evolution.py", line 5, in <module>
    project.import_media(r"C:\Users\dvyd\AppData\Roaming\REAPER\TrackTemplates\reaktor_mwave.RTrackTemplate")
  File "C:\Users\dvyd\AppData\Local\Programs\Python\Python37\lib\site-packages\reapy\core\project\project.py", line 172, in import_media
    valid_filepath = file_handler.validate_path(filepath)
  File "C:\Users\dvyd\AppData\Local\Programs\Python\Python37\lib\site-packages\reapy\tools\file_handler.py", line 40, in validate_path
    if file_ext not in READABLE_FORMATS : raise TypeError(f'"{fullPath_str}" file type "{file_ext}" is not supported by REAPER')
TypeError: "C:/Users/dvyd/AppData/Roaming/REAPER/TrackTemplates/reaktor_mwave.RTrackTemplate" file type ".rtracktemplate" is not supported by REAPER
Levitanus commented 2 years ago

There is appropriate API call, which you can find in reascript documentation and use via

from reapy import reascript-api as RPR
RPR.Function()

Also, you can load entire project as track template.

Pity, but I'm too busy now for making working example

d-vyd commented 2 years ago

Thanks @Levitanus . I wasn't sure if I had to use the reascript API. When you are less busy (if that ever happens), I'd love to hear how you use scripting with Reaper to pursue whatever you do in the music/audio realm.

Levitanus commented 2 years ago

@d-vyd , actually, all you need is the loading a track-template as project:

import reapy as rpr

pr = rpr.Project()
template = rpr.open_project("/path/to/my.RTrackTemplate")

Considering a question about making things based on ReaScript API and reapy DOM:

I remember that there was a hack with track-template loading, so I just moved to API documentation and checked at first the Main_openProject function.

In case when reapy really does not have OOP realization — it is quite normal to import native functions as described in readme:

import reapy
from reapy import reascript_api as RPR

pr = reapy.Project()

AUTHOR_SZ = 1024  # how many bytes allocate to get author name

(_, _, author, _) = RPR.GetSetProjectAuthor(pr.id, False, 'author', AUTHOR_SZ)
print(author)

But I prefer not to use native functions in my projects, as they cannot be statically analyzed. So I implement every «reapy function» I need as part of reapy project, then pull-request it.

Since @RomeoDespres is a very pedantic person, needs to joy every line of code in his project, many of community pull-requests are waiting for some author's refactoring and reflection. I really enjoy the way original library is made and consider @RomeoDespres as very talented programmer, but I suffer from need to hardcore my GitHub repository's branches into my projects, while I cannot just use pip package. A week ago, my reapy-based scripts for my ex-employer were broken as I've removed one of the old branches.

So, I want to maintain my fork of reapy as spin-off project, mainly with purpose to make community pulls move quick and being included into the pypi package (also with other name). But I still cannot decide:

Generally speaking, difficulties with synchronization are present already, as @RomeoDespres is developing a brand new midi API inspired by my pull, but it has some variance in API, which, alongside with the fact it is not finished yet, leads my projects to depend on my fork's solution. Which is the very reason I want to have "the fork" but not only GitHub branch)))

Your question, actually, returned me to the problem, and, maybe tonight, I will solve it at least for myself)))


Well, finally, I've pushed the fork into PyPi as reapy-boost. It breaks code-capability with reapy as all imports should start with reapy_boost, but I suppose, it will bring possibility to keep "all-in-one, on the edge" version of reapy.