Описание проблемы
По сути, я хотел бы воссоздать следующее изображение в 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
- Время атаки А
- Время распада 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}