13
0
livetrax/libs/aaf/ProTools.c
Robin Gareus 7593551e49
Import libAAF into Ardour's source-tree
tools/update_libaaf.sh - libaaf v0.1-85-g3e4c2cd
2023-11-27 23:24:54 +01:00

304 lines
11 KiB
C

/*
* Copyright (C) 2017-2023 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include "aaf/AAFIface.h"
#include "aaf/ProTools.h"
#define PROTOOLS_CLIP_NAME_FADE_EN_LEN 5 // +1
#define PROTOOLS_CLIP_NAME_FADE_DE_LEN 5 // +1
#define PROTOOLS_CLIP_NAME_FADE_JA_LEN 5 // +1
#define PROTOOLS_CLIP_NAME_FADE_FR_LEN 6 // +1
#define PROTOOLS_CLIP_NAME_FADE_ES_LEN 8 // +1
#define PROTOOLS_CLIP_NAME_FADE_ZH_CN_LEN 3 // +1
#define PROTOOLS_CLIP_NAME_FADE_ZH_TW_LEN 3 // +1
#define PROTOOLS_CLIP_NAME_FADE_KO_LEN 3 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN_LEN 20 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE_LEN 24 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES_LEN 32 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR_LEN 33 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA_LEN 8 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN_LEN 6 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW_LEN 6 // +1
#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO_LEN 11 // +1
/* English : "Fade " (Same as JA and DE) */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_EN[] = L"\x0046\x0061\x0064\x0065\x0020\x0000";
/* German : "Fade " (Same as JA and EN) */
// static const wchar_t PROTOOLS_CLIP_NAME_FADE_DE[] = L"\x0046\x0061\x0064\x0065\x0020\x0000";
/* Japanese : "Fade " (Same as EN and DE) */
// static const wchar_t PROTOOLS_CLIP_NAME_FADE_JA[] = L"\x0046\x0061\x0064\x0065\x0020\x0000";
/* French : "Fondu " */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_FR[] = L"\x0046\x006f\x006e\x0064\x0075\x0020\x0000";
/* Spanish : "Fundido" */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_ES[] = L"\x0046\x0075\x006e\x0064\x0069\x0064\x006f\x0020\x0000";
/* Chinese (S) : "淡变 " */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_ZH_CN[] = L"\x6de1\x53d8\x0020\x0000";
/* Chinese (T) : "淡變 " */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_ZH_TW[] = L"\x6de1\x8b8a\x0020\x0000";
/* Korean : "페이드" */
static const wchar_t PROTOOLS_CLIP_NAME_FADE_KO[] = L"\xd398\xc774\xb4dc\x0000";
/* English : "Sample accurate edit" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN[] = L"\x0053\x0061\x006d\x0070\x006c\x0065\x0020\x0061\x0063\x0063\x0075\x0072\x0061\x0074\x0065\x0020\x0065\x0064\x0069\x0074\x0000";
/* German : "Samplegenaue Bearbeitung" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE[] = L"\x0053\x0061\x006d\x0070\x006c\x0065\x0067\x0065\x006e\x0061\x0075\x0065\x0020\x0042\x0065\x0061\x0072\x0062\x0065\x0069\x0074\x0075\x006e\x0067\x0000";
/* Spanish : "Edición con precisión de muestra" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES[] = L"\x0045\x0064\x0069\x0063\x0069\x00f3\x006e\x0020\x0063\x006f\x006e\x0020\x0070\x0072\x0065\x0063\x0069\x0073\x0069\x00f3\x006e\x0020\x0064\x0065\x0020\x006d\x0075\x0065\x0073\x0074\x0072\x0061\x0000";
/* French : "Modification à l'échantillon près" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR[] = L"\x004d\x006f\x0064\x0069\x0066\x0069\x0063\x0061\x0074\x0069\x006f\x006e\x0020\x00e0\x0020\x006c\x0027\x00e9\x0063\x0068\x0061\x006e\x0074\x0069\x006c\x006c\x006f\x006e\x0020\x0070\x0072\x00e8\x0073\x0000";
/* Japanese : "サンプル精度編集" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA[] = L"\x30b5\x30f3\x30d7\x30eb\x7cbe\x5ea6\x7de8\x96c6\x0000";
/* Chinese (S) : "精确采样编辑" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN[] = L"\x7cbe\x786e\x91c7\x6837\x7f16\x8f91\x0000";
/* Chinese (T) : "精確取樣編輯" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW[] = L"\x7cbe\x78ba\x53d6\x6a23\x7de8\x8f2f\x0000";
/* Korean : "샘플 단위 정밀 편집" */
static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO[] = L"\xc0d8\xd50c\x0020\xb2e8\xc704\x0020\xc815\xbc00\x0020\xd3b8\xc9d1\x0000";
static int
is_rendered_fade (const wchar_t* clipName);
static int
is_sample_accurate_edit (const wchar_t* clipName);
static int
replace_clipfade_with_fade (AAF_Iface* aafi, aafiTimelineItem* Item);
int
protools_AAF (struct AAF_Iface* aafi)
{
int probe = 0;
/* TODO: CompanyName is "Digidesign, Inc." in ProTools 10.3.10.613 AAF, but what about since ? */
// if ( aafi->aafd->Identification.CompanyName && wcscmp( aafi->aafd->Identification.CompanyName, L"Digidesign, Inc." ) == 0 ) {
// probe++;
// }
if (aafi->aafd->Identification.ProductName && wcscmp (aafi->aafd->Identification.ProductName, L"ProTools") == 0) {
probe++;
}
if (probe == 1) {
return 1;
}
return 0;
}
static int
is_rendered_fade (const wchar_t* clipName)
{
return (memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_EN, PROTOOLS_CLIP_NAME_FADE_EN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ES, PROTOOLS_CLIP_NAME_FADE_ES_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_FR, PROTOOLS_CLIP_NAME_FADE_FR_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ZH_CN, PROTOOLS_CLIP_NAME_FADE_ZH_CN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_ZH_TW, PROTOOLS_CLIP_NAME_FADE_ZH_TW_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_FADE_KO, PROTOOLS_CLIP_NAME_FADE_KO_LEN) == 0);
}
static int
is_sample_accurate_edit (const wchar_t* clipName)
{
return (memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW_LEN) == 0) ||
(memcmp (clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO_LEN) == 0);
}
static int
replace_clipfade_with_fade (AAF_Iface* aafi, aafiTimelineItem* Item)
{
if (Item->type != AAFI_AUDIO_CLIP) {
return -1;
}
aafiAudioClip* audioClip = (aafiAudioClip*)Item->data;
aafPosition_t currentpos = audioClip->pos;
aafPosition_t currentlen = audioClip->len;
aafiTimelineItem* transItem = calloc (sizeof (aafiTimelineItem) + sizeof (aafiTransition), sizeof (char));
memset (transItem, 0x00, sizeof (aafiTimelineItem) + sizeof (aafiTransition));
transItem->type = AAFI_TRANS;
transItem->next = NULL;
transItem->prev = NULL;
transItem->data = calloc (sizeof (aafiTransition), sizeof (char));
aafiTransition* trans = transItem->data;
trans->len = audioClip->len;
trans->flags = AAFI_INTERPOL_NONE;
// debug( "%ls", audioClip->Essence->unique_file_name );
aafiAudioClip* prevClip = NULL;
aafiAudioClip* nextClip = NULL;
if (Item->prev != NULL) {
if (Item->prev->type == AAFI_AUDIO_CLIP) {
prevClip = (aafiAudioClip*)Item->prev->data;
// debug( "PREVIOUS POS %lu", prevClip->pos + prevClip->len );
// debug( "CURENT POS %lu", currentpos );
if (prevClip->pos + prevClip->len < currentpos - 1) {
prevClip = NULL;
}
}
}
if (Item->next != NULL) {
if (Item->next->type == AAFI_AUDIO_CLIP) {
nextClip = (aafiAudioClip*)Item->next->data;
if (is_sample_accurate_edit (nextClip->Essence->file_name)) {
if (Item->next->next != NULL) {
nextClip = (aafiAudioClip*)Item->next->next->data;
// debug( "NEXT POS %lu", nextClip->pos );
// debug( "CURENT POS %lu", currentpos + currentlen );
if (nextClip->pos != currentpos + currentlen + 1) {
nextClip = NULL;
}
} else {
nextClip = NULL;
}
} else {
// nextClip = (aafiAudioClip*)Item->next->data;
// debug( "NEXT POS %lu", nextClip->pos );
// debug( "CURENT POS %lu", currentpos + currentlen );
if (nextClip->pos != currentpos + currentlen) {
nextClip = NULL;
}
}
}
}
trans->time_a = calloc (2, sizeof (aafRational_t));
trans->value_a = calloc (2, sizeof (aafRational_t));
trans->time_a[0].numerator = 0;
trans->time_a[0].denominator = 0;
trans->time_a[1].numerator = 1;
trans->time_a[1].denominator = 1;
if (prevClip && nextClip) {
// debug( ":: XFADE" );
trans->flags |= AAFI_TRANS_XFADE;
trans->value_a[0].numerator = 0;
trans->value_a[0].denominator = 0;
trans->value_a[1].numerator = 1;
trans->value_a[1].denominator = 1;
} else if (prevClip) {
// debug( ":: FADE OUT" );
trans->flags |= AAFI_TRANS_FADE_OUT;
trans->value_a[0].numerator = 1;
trans->value_a[0].denominator = 1;
trans->value_a[1].numerator = 0;
trans->value_a[1].denominator = 0;
} else if (nextClip) {
// debug( ":: FADE IN" );
trans->flags |= AAFI_TRANS_FADE_IN;
trans->value_a[0].numerator = 0;
trans->value_a[0].denominator = 0;
trans->value_a[1].numerator = 1;
trans->value_a[1].denominator = 1;
}
if (Item->prev) {
Item->prev->next = transItem;
transItem->prev = Item->prev;
} else {
aafiAudioTrack* audioTrack = NULL;
foreach_audioTrack (audioTrack, aafi)
{
if (audioTrack->Items == Item) {
audioTrack->Items = transItem;
}
}
transItem->prev = NULL;
}
if (Item->next) {
Item->next->prev = transItem;
}
transItem->next = Item->next;
aafi_freeTimelineItem (&Item);
return 0;
}
int
protools_post_processing (AAF_Iface* aafi /*, enum protools_options flags*/)
{
aafiAudioTrack* audioTrack = NULL;
foreach_audioTrack (audioTrack, aafi)
{
aafiTimelineItem* audioItem = audioTrack->Items;
while (audioItem != NULL) {
if (audioItem->type != AAFI_AUDIO_CLIP) {
audioItem = audioItem->next;
continue;
}
aafiAudioClip* audioClip = (aafiAudioClip*)audioItem->data;
wchar_t* clipName = audioClip->Essence->file_name;
if ((aafi->ctx.options.protools & PROTOOLS_REPLACE_CLIP_FADES) && is_rendered_fade (clipName)) {
replace_clipfade_with_fade (aafi, audioItem);
audioItem = audioTrack->Items;
continue;
} else if ((aafi->ctx.options.protools & PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT) && is_sample_accurate_edit (clipName)) {
aafi_removeTimelineItem (aafi, audioItem);
audioItem = audioTrack->Items;
continue;
}
audioItem = audioItem->next;
}
}
return 0;
}