Descrição do Problema
Basicamente, gostaria de recriar a seguinte imagem no TikZ:
http://krashan.ppa.pl/articles/u1synth/adsr.png
Isto se resume à questão decomo multiplicar uma onda senoidal por uma função linear por partes em TikZ/pgf.
Restrições e liberdades
- As cores da imagem original não precisam ser reproduzidas :)
- Gostaria de resolver este problema sem precisar armazenar dados em um arquivo externo
- Estou feliz em usar
pgfplots
e/oupgfmath
Exemplo mínimo (não) funcional
Tenho a sensação de que o mecanismo apropriado para atacar esse problema no TikZ/pgf é o mecanismo de declaração de função (mas não tenho certeza se estou certo).
No exemplo abaixo, implementei apenas a primeira parte da função linear por partes, para tentar multiplicá-la por uma função seno. Porém, quando faço isso, todo o gráfico desaparece (comente a linha marcada TODO
no exemplo abaixo para confirmar).
\documentclass{article}
\usepackage{pgfplots}
% Declare (first part of) piecewise linear function
\pgfmathdeclarefunction{p}{1}{%
\pgfmathparse{ ((x>=0) && (x<=50))*x/50 }
}
\begin{document}
\begin{tikzpicture}[domain=0:500]
\begin{axis}
% Plot piecewise linear function
\addplot[thick, blue]{p(x)};
% Plot sine function
\addplot[red, samples=500, smooth]{sin(20*x)};
% Plot product of both. TODO: Makes entire plot disappear
%\addplot[thick, green, samples=500, smooth]{sin(30*x)*p(x)};
\end{axis}
\end{tikzpicture}
\end{document}
Ideias bônus para implementação
- O sinal máximo da função linear por partes deve ser sempre +1
- o eixo x deve representar milissegundos
- A duração total do envelope deve ser em torno de 500ms, mas:
- Seria bom se os seguintes parâmetros pudessem ser definidos pelo usuário:
- Tempo total T=A+D+S+R
- Tempo de ataque A
- Tempo de decaimento D
- Tempo de liberação R
- Manter o nível L
- O tempo de sustentação S seria derivado automaticamente como S = T-(A+D+R)
Responder1
Você pode definir uma função linear por partes multiplicando as partes pelas condições que verificam o intervalo e adicionando-as. Então você só precisa multiplicar a função seno pela função linear por partes.
Qual é o problema com sua solução?
Na verdade, falta apenas um caractere: Adicione um sinal de porcentagem após a \pgfmathparse
expressão:
\pgfmathdeclarefunction{p}{1}{%
\pgfmathparse{ ((x>=0) && (x<=50))*x/50 }% <<<<<<<<
}
Sem ele, um espaço será adicionado à esquerda do gráfico para cada chamada da função, de modo que os gráficos saiam da página para a direita.
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{calc}
\pgfmathdeclarefunction{ADSR}{1}{%
\pgfmathparse
{( #1<=\pA )*(#1/\pA) +%
(and(#1>\pA , #1<=(\pA+\pD))*(#1*(-\pL)/\pD + 1 + \pA*\pL/\pD) +%
(and(#1>(\pA+\pD), #1<=(\pT-\pR))*(1-\pL) +%
(and(#1>(\pT-\pR), #1<=\pT )*((1-\pL)/\pR*(-#1+\pT))
}%
}
\begin{document}
\begin{tikzpicture}
\newcommand\pT{500} % total
\newcommand\pA{100} % attack
\newcommand\pD{100} % decay
\newcommand\pR{100} % release
\newcommand\pL{0.2} % sustain level
\newcommand\pF{50} % frequency (not in Hz, but proportional)
\begin{axis}[x=0.2mm,y=2cm]
\addplot[domain=0:\pT, green, samples=5000] {ADSR(x)*sin(\pF*x)};
\addplot[domain=0:\pT, red, samples=100] {ADSR(x)};
\end{axis}
\end{tikzpicture}
\end{document}