Descrição do Problema

Descrição do Problema

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 pgfplotse/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 TODOno 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 \pgfmathparseexpressã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.

insira a descrição da imagem aqui

\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}

informação relacionada