pyaaf2 icon indicating copy to clipboard operation
pyaaf2 copied to clipboard

How to preserve link to source files after downloading an aaf from the server?

Open Dylan-Buth opened this issue 2 years ago • 3 comments

This may be a basic question. I'm pretty new to aaf files in general and am having trouble understanding this part.

We're building an aaf file server-side, from WAV files. We then let the user download a zip that includes the aaf, and corresponding wav files. The problem is, once the user downloads it, the link is wrong. For example, a SourceMob has a locator object, with a urlstring pointing to the absolute path of the wav file on the server. Is there a way to set that locator to a path, relative to the aaf file? (Ex. ./source-wav-1.wav) Or is there another solution to this problem that I'm missing?

Logic Pro seems to handle it best, prompting the user to select the location of files it can't find. Pro Tools just gives an error.

Dylan-Buth avatar Dec 01 '22 17:12 Dylan-Buth

The AAF Edit Protocol says relative paths are supported. If pro tools supports them is another story. I'm not entirely sure the syntax, the spec says to follow RFC 2396. Unfortunately I don't have access to pro tools to test.

markreidvfx avatar Dec 01 '22 22:12 markreidvfx

Hi, I try to necro-bump this issue, but I'm facing the same "problem". I really hate that the AAF produced by Logic Pro has these damn absolute path... It's completely stupid: I'm saving the AAF to pass my project (song) to a guy using another DAW and the best I can do is a damn file not easily usable if moved from the original directory on the original computer used to export... It's a nonsense...

I also hate that Logic Pro is exporting all the wav files in a directory called "Audio Files" (let's start hating the use of the space...). Two songs exported? The second is "Audio Files 2". Completely idiot...

So I wrote a pyaaf2 script to change the AAF file to change this path.

It took a while but I managed to make it work (so now I can move and rename the dir with the wav files where I like) but I ended not being able to "relativify" the paths...

None of the commented ones are working:

path_in = "file:///Users/bozzo/Documents/Musica/GarageBand/NuvolaNera/Audio%20Files"
path_out = "file:///Users/bozzo/Documents/Musica/GarageBand/NuvolaNera/NuvolaNera_Files"
#path_out = "file://NuvolaNera_Files"
#path_out = "file://.NuvolaNera_Files"
#path_out = "file://./NuvolaNera_Files"
#path_out = "./NuvolaNera_Files"

There's something I miss in how I write the path?

Script attached (I had to add .txt...) and full code copied below if someone would need it. aaf_editor.py.txt

Matteo

import aaf2
import chardet

source_file = "./NuvolaNera.AAF"
dest_file = "./NuvolaNera_edited.AAF"

path_in = "file:///Users/bozzo/Documents/Musica/GarageBand/NuvolaNera/Audio%20Files"
path_out = "file:///Users/bozzo/Documents/Musica/GarageBand/NuvolaNera/NuvolaNera_Files"
#path_out = "file://NuvolaNera_Files"
#path_out = "file://.NuvolaNera_Files"
#path_out = "file://./NuvolaNera_Files"
#path_out = "./NuvolaNera_Files"

path_in_enc = path_in.encode('utf-16le','strict')
path_out_enc = path_out.encode('utf_16le','strict')

def copy_mobs(a, b):
    for mob in a.content.mobs:
        if mob.mob_id not in b.content.mobs:
            # copy the mob from file a into file b
            mob_copy = mob.copy(root=b)
            b.content.mobs.append(mob_copy)

def copy_essence_data(a, b):
    for essence_data in a.content.essencedata:
        if essence_data.mob_id not in b.content.essencedata:
            # copy the essence data from file a into file b
            essence_data_copy = essence_data.copy(root=b)
            b.content.essencedata.append(essence_data_copy)

with aaf2.open(dest_file, "w") as f_dest:
    with aaf2.open(source_file, "r") as f:

        #        f.dump()
        #        f.content.dump()

        f_dest.dictionary.update(f.dictionary)
        
        for mm in f.content.mobs:
            print("name: ", mm.name)
            if ".wav" in mm.name:
                #                mm.dump()
                #                print(mm.keys())
                ed = mm.get("EssenceDescription")
                #                print(type(ed))
                if ed is not None:
                    #                    print("    Ess.Descr. name: ", ed.name)
                    p1d = ed.propertydef
                    #                    print("    Prop.1.Def. name: ", p1d.name)
                    r1 = ed.value
                    #                    print(r1)
                    d1 = ed.data
                    #                    print(d1.decode())
                    #                    print(ed.object.keys())
                    ll = ed.object.get("Locator")
                    #                    print(ll.value)
                    nll = ll.value
                    nl = nll[0]
                    #                    print(nl.keys())
                    us = nl.get("URLString")
                    #                    print(type(us))
                    #                    print(type(us.data))
                    #                    print(us.data)
                    #                    the_encoding = chardet.detect(us.data)['encoding']
                    #                    print(the_encoding)
                    print(us.data.decode())
                    ss = us.data.decode('utf_16le','strict')
                    #                    print(type(ss))
                    #                    print("Len: ", len(ss))
                    ss = ss.replace(path_in, path_out)
                    #                    data_new = us.data.replace(path_in_enc, path_out_enc)
                    #                    ss_new = data_new.decode()
                    #                    print(ss_new)
                    print(ss)
                    us.data=ss.encode('utf_16le','strict')
                    print(mm.get("EssenceDescription").object.get("Locator").value[0].get("URLString").data.decode())
        copy_mobs(f, f_dest)
        copy_essence_data(f, f_dest)

bozzochet avatar Aug 12 '24 07:08 bozzochet