问题描述
我基本上想在 TikZ 中重新创建以下图像:
http://krashan.ppa.pl/articles/u1synth/adsr.png
这可以归结为如何在 TikZ/pgf 中将正弦波与分段线性函数相乘。
限制与自由
- 不需要复制原始图像的颜色:)
- 我想解决这个问题,而不必将数据存储在外部文件中
- 我很乐意使用
pgfplots
和/或pgfmath
最小(非)工作示例
我感觉解决 TikZ/pgf 中此问题的适当机制是其函数声明机制(但我不确定我是否正确)。
在下面的例子中,我仅实现了分段线性函数的第一部分,尝试将其与正弦函数相乘。但是,当我这样做时,整个图都消失了(注释掉TODO
下面例子中标记的行以确认)。
\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}
实施的额外想法
- 分段线性函数的信号最大值应始终为 +1
- x 轴应代表毫秒
- 信封的总持续时间应约为 500 毫秒,但是:
- 如果用户可以设置以下参数就好了:
- 总时间T=A+D+S+R
- 攻击时间A
- 衰减时间D
- 释放时间R
- 维持水平 L
- 持续时间 S 将自动推导为 S = T-(A+D+R)
答案1
你可以通过将各部分与检查区间的条件相乘并将它们相加来定义分段线性函数。然后你只需将正弦函数与分段线性函数相乘即可。
您的解决方案存在什么问题?
事实上,只缺少一个字符:在表达式后添加百分号\pgfmathparse
:
\pgfmathdeclarefunction{p}{1}{%
\pgfmathparse{ ((x>=0) && (x<=50))*x/50 }% <<<<<<<<
}
如果没有它,每次调用该函数时都会在图的左侧添加一个空格,因此图会向页面右侧移出。
\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}