Sum to Zero

um blog sobre áudio, masterização, design de estúdios & acústica

3 de janeiro de 2026

Configurar metadata no Reaper em sessões de masterização

A gestão de metadata importa mais do que parece na masterização. Um arquivo digital bem organizado e pesquisável é essencial para qualquer estúdio profissional. Os clientes pedem ficheiros anos depois do processo estar concluído, e uma boa metadata garante que esses ficheiros se encontram sem drama.

Metadata em falta ou incorrecta também cria problemas reais na distribuição digital. E apesar dos números do streaming, os CDs continuam a ser uma parte significativa da indústria. Os músicos valorizam o CD-TEXT, o que torna a inserção precisa de metadata em ficheiros master DDP uma exigência standard.

Uma razão pela qual continuo a usar o Reaper para masterização é que gere tudo num único projecto: processamento, sequenciação e exportação. Ou seja, posso guardar a metadata de um lançamento directamente na timeline e automatizar as exportações.

A forma como giro isto é anexando a metadata directamente às regiões (Regions).

Porquê regiões?

As regiões no Reaper são uma escolha natural para masterização, especialmente para material delimitado no tempo, como uma música individual, um álbum ou movimentos numa peça de música clássica.

Mesmo para um disco gapless (sem pausas), as regiões ajudam a visualizar onde começam e acabam partes específicas. Permitem saltar entre secções instantaneamente e fazer cortes para processar secções separadamente se necessário, mesmo que no final se exporte tudo como um único ficheiro contínuo.

Inspirei-me no sistema nativo do Reaper desenhado para exportação de DDP e desenvolvi um modelo padrão de nomeação de regiões:

#TITLE=Title|PERFORMER=Artist|COMPOSER=Composer|LYRICIST=Lyricist|ISRC=PTKNU2600001|VERSION=1|VINYL=A1

Para cada região, uso este modelo e edito os campos para essa faixa específica. Isto permite inserir dados granulares que podem ser recuperados mais tarde usando wildcards durante o processo de render.

Detalhe dos campos

Desta forma, sequências distintas para lançamentos digitais e vinil ficam sempre guardadas dentro do projecto.

Metadata global do lançamento

As regiões tratam dos detalhes ao nível da faixa, mas também é preciso campos para o lançamento inteiro (ex: Artista do Álbum, Título do Álbum). Guardo essa informação nas Definições do Projecto (Project Settings):

Exportar ficheiros digitais

Assim que as regiões estiverem nomeadas, o próximo passo é instruir o Reaper a usar esse texto como metadata.

Na janela Render to File:

Reaper Render Metadata com wildcards

Imagem 1. Convenção de nomenclatura para inserir metadata no Reaper usando wildcards.

Padrão de nomeação de ficheiros

Também uso estes wildcards para gerir os nomes dos ficheiros na exportação. O padrão habitual do nosso estúdio é:

$region(PERFORMER)[|] - $regionnumber $region(#TITLE)[|] v$region(VERSION)[|]

Isto gera automaticamente nomes de ficheiros como: Nome do Artista - 01 Título da Música v1.wav

Gerir DDPs e CD-TEXT

O sistema acima funciona bem para ficheiros digitais, mas os CDs de Áudio (imagens DDP) requerem uma abordagem diferente. Os DDPs dependem de markers específicos para identificar pontos de início de faixa, índices e CD-TEXT.

O Reaper tem suporte nativo para DDP, mas colocar markers manualmente e escrever a metadata para cada um é entediante e propenso a erros. Felizmente, o Reaper permite scripting. Escrevi um script em Lua que automatiza todo este processo. O script extrai a informação já inserida nas regiões, limpa caracteres especiais e converte-os nos markers específicos necessários para um DDP válido.

O script faz duas coisas:

--[[
* ReaScript Name: Convert Regions to DDP Markers
* Description: Creates DDP markers (!, Tracks, @) with full metadata integration and text sanitization.
* Author: Knurl Mastering
--]]

local is_new_value, filename, section_ID, command_ID, mode, resolution, val = reaper.get_action_context()

-----------------------------------------------------------
-- 1. TOOLBAR FLASH LOGIC
-----------------------------------------------------------
local flash_duration = 0.1 
local start_time = 0

function MonitorFlash()
	local now = reaper.time_precise()
	if now - start_time < flash_duration then
		reaper.defer(MonitorFlash) 
	else
		reaper.SetToggleCommandState(section_ID, command_ID, 0)
		reaper.RefreshToolbar2(section_ID, command_ID)
	end
end

function TriggerFlash()
	reaper.SetToggleCommandState(section_ID, command_ID, 1)
	reaper.RefreshToolbar2(section_ID, command_ID)
	start_time = reaper.time_precise()
	MonitorFlash()
end

-----------------------------------------------------------
-- 2. TEXT SANITIZATION
-----------------------------------------------------------
local replacements = {
	["á"]="a", ["à"]="a", ["ã"]="a", ["â"]="a", ["ä"]="a", ["å"]="a",
	["é"]="e", ["è"]="e", ["ê"]="e", ["ë"]="e",
	["í"]="i", ["ì"]="i", ["î"]="i", ["ï"]="i",
	["ó"]="o", ["ò"]="o", ["õ"]="o", ["ô"]="o", ["ö"]="o",
	["ú"]="u", ["ù"]="u", ["û"]="u", ["ü"]="u",
	["ç"]="c", ["ñ"]="n", ["ý"]="y",
	["Á"]="A", ["À"]="A", ["Ã"]="A", ["Â"]="A", ["Ä"]="A", ["Å"]="A",
	["É"]="E", ["È"]="E", ["Ê"]="E", ["Ë"]="E",
	["Í"]="I", ["Ì"]="I", ["Î"]="I", ["Ï"]="I",
	["Ó"]="O", ["Ò"]="O", ["Õ"]="O", ["Ô"]="O", ["Ö"]="O",
	["Ú"]="U", ["Ù"]="U", ["Û"]="U", ["Ü"]="U",
	["Ç"]="C", ["Ñ"]="N", ["Ý"]="Y"
}

function sanitize_text(str)
	if not str then return "" end
	-- Step A: Replace accented chars
	for k, v in pairs(replacements) do
		str = string.gsub(str, k, v)
	end
	-- Step B: Allow # = | and standard punctuation
	str = string.gsub(str, "[^%w%s%-%_%.%,%!%?%'%\"%(%)%#%=%|]", "")
	return str
end

-----------------------------------------------------------
-- 3. METADATA HELPERS
-----------------------------------------------------------
function get_project_title()
	local retval, title = reaper.GetSetProjectInfo_String(0, "PROJECT_TITLE", "", false)
	if retval and title ~= "" then
		return sanitize_text(title)
	else
		return "Unknown Album"
	end
end

function get_project_author()
	local retval, author = reaper.GetSetProjectInfo_String(0, "PROJECT_AUTHOR", "", false)
	if retval and author ~= "" then
		return sanitize_text(author)
	else
		return "Unknown Artist"
	end
end

function create_colored_marker(pos, name, id)
	-- Dark Grey (64, 64, 64)
	local r, g, b = 64, 64, 64
	local color = reaper.ColorToNative(r, g, b) | 0x1000000
	
	reaper.AddProjectMarker2(0, false, pos, 0, name, id, color)
end

-----------------------------------------------------------
-- 4. MAIN LOGIC
-----------------------------------------------------------
function main()
	-- CHECK: Do regions exist?
	local ret, num_markers, num_regions = reaper.CountProjectMarkers(0)
	if num_regions == 0 then return end 
	
	TriggerFlash()
	reaper.Undo_BeginBlock()

	local i = 0
	local regions_to_process = {}
	local last_region_end = 0

	-- LOOP: Gather all Regions
	while true do
		local retval, isrgn, pos, rgnend, name, markrgnindexnumber = reaper.EnumProjectMarkers(i)
		if retval == 0 then break end
		
		if isrgn then
			table.insert(regions_to_process, {
				pos = pos,
				name = name,
				id = markrgnindexnumber
			})
			
			-- Find the absolute end of the album
			if rgnend > last_region_end then
				last_region_end = rgnend
			end
		end
		i = i + 1
	end

	-- A. CREATE START MARKER (ID 99)
	create_colored_marker(0, "!", 99)

	-- B. CREATE TRACK MARKERS
	for _, rgn in ipairs(regions_to_process) do
		local clean_name = sanitize_text(rgn.name)
		create_colored_marker(rgn.pos, clean_name, rgn.id)
	end

	-- C. CREATE END MARKER
	-- Format: @ALBUM|PERFORMER=Artist
	local album_title = get_project_title()
	local album_artist = get_project_author()
	local end_marker_name = "@" .. album_title .. "|PERFORMER=" .. album_artist
	
	-- ID: Number of Regions + 1
	local end_marker_id = num_regions + 1
	
	create_colored_marker(last_region_end, end_marker_name, end_marker_id)

	reaper.Undo_EndBlock("Create DDP Markers", -1)
end

main()
Tags: #Masterização #Reaper #Scripts