攻击,衰减,持续,释放


47

声音合成器使用包络发生器来控制声音的某些参数(例如整体响度)如何随时间变化。在许多合成器中,信封是由四个参数定义的,如维基百科的下图所示:

  • 起音时间(A):第一次按下该键时,信封从零开始达到最大电平所花费的时间。
  • 衰减时间(D):包络达到指定维持水平所需的时间。
  • 延音等级(S):在初始击打和衰减之后,只要按下琴键,该等级就保持不变。
  • 释放时间(R):释放键时信封到达零的时间。

在此处输入图片说明

挑战

输入四个参数A,D,S,R并绘制包络线

参数将是0到127之间的整数值

最高水平(在攻击阶段结束时达到)将被假定为127

维持电平水平片段将假定具有持续时间64(在实际声音中,该持续时间不是固定的,而是由按住琴键的时间决定的)。

格式和更多详细信息

输出应为光栅或矢量格式的图像。如果是栅格,则折线应在水平方向上至少占据50个像素。

图像可以以标准图像格式显示或生成为文件。可以将文件写入磁盘,也可以将其确切内容输出到STDERR或作为函数返回参数输出。

图形只需要包含定义信封的折线。每个轴的比例可以自由选择。其他元素(如轴线,数字标签或线条颜色)是可选的。

输入方式和格式像往常一样灵活。例如,您可以采用任意顺序的四个数字,也可以包含它们的数组。可以提供程序或功能。禁止出现标准漏洞

以字节为单位的最短代码获胜。

测试用例

输入采用格式[A D S R]。请注意,每个图中的比例都是不同的(根据比例可以自由选择的规则)

[15 30 70 40]

在此处输入图片说明

[64 64 64 64]

在此处输入图片说明

[0 10 50 80]

在此处输入图片说明

[0 0 90 80]

在此处输入图片说明

[5 50 0 0]

在此处输入图片说明

[5 50 0 80]

在此处输入图片说明

[24 32 127 48]

在此处输入图片说明



@Ben该参考文献也有意图:-)我爱睡眠剥夺
路易斯·门多

Answers:


7

MATL,31 22字节

Oii64ivYsO127itO5$h&XG

接受订购的四个独立的输入ADRS

MATL Online上试用

说明

0   % Push a literal 0 to the stack
ii  % Grab the first two inputs
64  % Push the number literal 64 to the stack
i   % Grab the third input
v   % Vertically concatenate all values
Ys  % Compute the cumulative sum
0   % Push the number literal 0 to the stack
127 % Push the number literal 127 to the stack
i   % Grab the fourth input
t   % Duplicate the fourth input
O   % Push the number literal 0 to the stack
5$h % Concatenate the last 5 elements on the stack
&XG % Plot the result using the first array as x and second array as y

在此处输入图片说明


43

TikZ,195 193 181 177 172 167 163 160 159字节

感谢David Carlisle 在这里的有用回答

\documentclass[tikz]{standalone}\begin{document}\tikz\def~#1{\typein[#1];}~\a~\s~\d~\r\def\u{)--(\a+\d}\draw(,)--(\a,127\u,\s\u+64,\s\u+\r+64,);\end{document}

是的,您没听错TikZ

说明

这使用了两种技术来实现其目标。首先是输入。大多数人可能不知道L A T E X可以接受输入。好吧,可以。这是通过命令实现的\typein。这将停止编译器,并在将其分配给变量时要求用户输入。

另一个主要技术是使用\def\def在提克兹(Tikz)实在是太强大了。它实质上定义了一段代码,并将其粘贴到调用变量的所有位置。在此代码中,我们定义了两件事,\typein[#1]{}以便我们可以轻松地分配变量,并且)--(\a+\d因为该代码在非高尔夫版本中显示了很多次。

这是代码的两个版本(无包装):

打高尔夫球:

\documentclass[tikz]{standalone}\begin{document}\tikz\def~#1{\typein[#1];}~\a~\s~\d~\r\def\u{)--(\a+\d}\draw(,)--(\a,127\u,\s\u+64,\s\u+\r+64,);\end{document}

取消高尔夫:

\typein[\a]{}\typein[\s]{}\typein[\d]{}\typein[\r]{}\draw(0,0)--(\a,127)--(\a+\d,)--(\a+\d+64,)--(\a+\d+\r+64,0);

图片:

由于我无法直接上传pdf图片,并且将其转换为其他格式似乎会导致该行完全消失,因此,在“预览”中打开该图片时,它的外观如下所示(此图片的输入为[64 64 64 64]):

预览图片

如您所见,它非常薄。但是,由于它是PDF图像而不是光栅图像,因此不必符合厚度要求。


12
我真的很佩服您非常了解TikZ,这是您想到的第一个解决方案。(如果不是,那将是传说会记住的)
Right Leg

1
不行input tikz\begin{document}
致命

5
图片呢?😉
Sarge的罗宋汤

您实际上是如何渲染的?pdflatex adsr.tex似乎不起作用。-哦,等等,它确实有效,我没想到它会请求交互式输入!

如果操作正确,@ WheatWizard imagemagick可以很好地转换PDF
Sarge Borsch

20

Python 2,83 80 79字节

from turtle import*
def f(A,D,S,R):X=A+D+64;map(goto,[A,A+D,X,X+R],[127,S,S,0])

在线尝试(83字节版本,因为它可以在线运行)

请注意,由于画布的工作方式,某些输出可能无法使用Trinket完全看到。如果您希望Python更好地工作,则需要下载并安装Python。

取消高尔夫:

from turtle import*
A,D,S,R=input()
goto(A,127)
goto(A+D,S)
goto(A+D+64,S)
goto(A+D+64+R,0)

此版本在Trinket中不起作用,因为Trinket不支持输入值的拆包。


您可以map在Python 2中使用lambda A,D,S,R:map(goto,[A,A+D,A+D+64,A+D+R+64],[127,S,S,0])
xnor

@xnor我SuspensionError: Cannot call a function that blocks or suspends here on line undefined in main.py上了Trinket。您确认它有效吗?我不确定该错误是否是Trinket特有的。
mbomb007'2

在2.7.12中为我工作。
xnor

@xnor Mmk,谢谢。这可能是Skulpt中的限制。
mbomb007 '17

我向Skulpt github存储库提交了该程序的简单版本作为示例,他们认为这是一个不错的发现。希望他们能够解决它,但是他们的“乌龟冲刺”的步伐似乎要走得多。
mbomb007 '17

17

Mathematica,61 58字节

ListLinePlot[{Accumulate@{0,##3,64,#2},{0,127,#,#,0}}]&

是Mathematica 的运算符,Transpose并显示为上标T

按顺序获取参数S, R, A, D并返回矢量图形对象。

所有七个测试用例的结果:

在此处输入图片说明 点击查看大图。


那很快!
路易斯·门多

+1教我ListLinePlot:)还有一个ListStepPlot-太有用了!
格雷格·马丁

12

R,66 63字节

function(A,D,S,R)plot(cumsum(c(0,A,D,64,R)),c(0,127,S,S,0),"l")

显示图像,轴实验室为cumsum(c(0,A,D,64,R))c(0,127,S,S,0),以及轴线和数字标签。

感谢@Zahiro Mor削减了3个字节

先前的答案:

function(A,D,S,R)plot(c(0,A,A+D,b<-A+D+64,b+R),c(0,127,S,S,0),"l")

2
您可以cumsum(c(0,A,D,64,R)) 用来替换图中的第一项。与cumsum,您将不需要b把戏并且仍然刮胡子3个字节:) function(A,D,S,R)plot(cumsum(c(0,A,D,64,R)),c(0,127,S,S,0),"l")
Zahiro Mor

11

Matlab,50个字节

@(A,D,S,R)plot(cumsum([0,A,D,64,R]),[0,127,S,S,0])

这将产生一个匿名函数“ ans”,必须将其称为ans(A,D,S,R)。


9

JavaScript(ES6)+ HTML,126 + 23 = 149

c=O.getContext`2d`;c.moveTo(a=0,z=O.height=128);g=(y,x=prompt())=>c.lineTo(a+=+x,y)||g;g(0)(s=z+~prompt())(s,64)(z);c.stroke()
<canvas id=O width=512>

按顺序一次输入一个A, S, D, R


9

的JavaScript(ES6),114个 111字节

f=(a,d,s,r)=>`<svg width=446 height=128><path stroke=red fill=none d=M0,127L${a},0l${d},${127-s}h64l${r},${s}>`
<div oninput=o.innerHTML=f(a.value,d.value,s.value,r.value)><input type=number value=0 min=0 max=127 id=a><input type=number value=63 min=0 max=127 id=d><input type=number value=127 min=0 max=127 id=s><input type=number value=0 min=0 max=127 id=r><div id=o><svg width=446 height=128><path stroke=red fill=none d=M0,127L0,0l63,0h64l0,127 /></svg>

返回适用于的SVG图片innerHTML。为有效的XML添加18个字节。


实时更新图形真是太好了!
路易斯·门多

太好了,我应该在某个时候学习SVG语法。也许给<input>s 添加默认值?
ETHproductions '17

@ETHproductions您是否有任何特定的默认值?(鉴于设置默认值实际上并不会触发初始图形……)
Neil

我只是在想64,64,64,64。通常,我会为默认输入对正确的输出进行硬编码,但是我知道在这里很难做到……
ETHproductions

8

Haskell,112110字节

import Graphics.Gloss
(a#d)s r=display(InWindow""(600,300)(0,0))red$line$zip(scanl(+)0[a,d,64,r])[0,127,s,s,0]

用法示例:(0#10) 50 80

广告信封

这使用了Gloss库。的display函数需要一个窗口绘制在(此处为:无标题的窗口(""),尺寸600×300,位置(0,0)在桌面上),背景色(red)和图片女巫是沿着通过压缩和解的累积和取得的路径的线[0,a,d,64,r]= [0,a,a+d,a+d+64,a+d+64+r]作为x坐标和[0,127,s,s,0]作为y坐标。

编辑:感谢@xnor 2个字节!


应该写得短些scanl(+)0[a,d,64,r]
xnor

5

处理中,134108 + 14(调用size)= 148122字节

首先,我们需要调用size程序中的某个位置,以使输出适合窗口(默认为100x100)。

size(400,400);

这是实际的功能:

void g(int a,int b,int c,int d){line(0,127,a,0);line(a,0,b+=a,c=127-c);line(b,c,b+=64,c);line(b,c,b+d,127);}

像这样称呼它 f(15,20,70,40);

屏幕截图

15, 20, 70, 40

图片


我的新答案比旧答案更直接,但是我更喜欢旧答案(即使更大)。

旧答案(148字节)

size(400,400);

和两个功能

void f(int[]v){translate(0,127);l(v[0],-127);l(v[1],127-v[2]);l(64,0);l(v[3],v[2]);}void l(int x,int y){line(0,0,x,y);translate(x,y);}

像这样调用,f(int_array_containing_values);结果将类似于:f(new int[]{15,20,70,40});


4

SmileBASIC,90个字节

INPUT A,D,S,R
B=A+D+64W=#Y-S
GLINE.,#Y,A,0GLINE A,0,A+D,W
GLINE A+D,W,B,W
GLINE B,W,B+R,#Y

4

PHP,149130字节

[,$a,$d,$s,$r]=$argv;imagepolygon($i=imagecreatetruecolor(446,127),[0,127,$a,0,$d+=$a,$s,$d+=64,$s,$d+$r,127],5,999);imagepng($i);

从命令行参数获取输入,将图像(黑底蓝字的PNG)写入stdout。需要PHP 7.1或更高版本。

用法,例如

# any OS with ImageMagick:
php -r '<code>' <parameters> | display

# linux with feh:
php -r '<code>' <parameters> | feh

+4个字节(适用于较早的PHP):替换[,$a,$d,$s,$r]list(,$a,$d,$s,$r)


那里有一个小技巧:imageopenpolygon在画布外部绘制完工的多边形线,而不是用来隐藏基线。(y = 127仅显示在高度> = 128的图像上。)

我本可以用99或9而不是999保存更多的颜色;但是这些很难在黑色上看到。:)


3

Bash + grace,70字节

t=$[$1+$2]
echo "0 0
$1 127
$t $3
$[t+64] $3
$[t+64+$4] 0">f
xmgrace f

该脚本将f每个点的坐标写入文件,并且xmgrace(GUI版本)读取文件并默认使用线显示图。

运行

./plot_ADSR.sh 15 30 70 40

输出:(打印屏幕)

15 30 70 40

我认为,如果可以接受输入,可以直接通过宽限脚本完成此操作,但是我不熟悉其语法。我会调查一下。

说明:

t=$[$1+$2]          # store the value of (A+D) for later usage
echo "0 0           # start writing the coordinates to file "f", first the origin
$1 127              # then (A, 127)
$t $3               # then (A + D, S)
$[t+64] $3          # then (A + D + 64, S)
$[t+64+$4] 0">f     # then (A + D + 64 + R, 0)
xmgrace f           # call xmgrace to plot the generated XY file

2

去吧,947个 915 506字节

这远非优化,而是在参与这些问题时尝试学习语言。随时指出我可以做什么。

固定影像

浓缩:

package main;import (."os";."image";k"image/png";c"image/color";."strconv";."math");func main(){g:=NewRGBA(Rect(0,0,127*4,127));a,_:=ParseFloat(Args[1],4);d,_:=ParseFloat(Args[2],4);s,_:=ParseFloat(Args[3],4);r,_:=ParseFloat(Args[4],4);z:=[5][]float64{{0,0},{a,127},{a+d,s},{a+d+64,s},{a+d+64+r,0}};for i:=1;i<len(z);i++{v,w,x,y:=z[i-1][0],z[i-1][1],z[i][0],z[i][1];m:=(y-w)/(x-v);t:=y-m*x;for v<=x{g.Set(int(Ceil(v)),127-int(Ceil(w)),c.RGBA{0,0,0,255});v+=.01;w=m*v+t}};f,_:=Create("o.png");k.Encode(f,g)}

不凝聚:

package main

import (
    ."os"
    ."image"
    k"image/png"
    c"image/color"
    ."strconv"
    ."math"
    "fmt"
)

func main(){
    g := NewRGBA(Rect(0, 0, 127*4, 127))

    a, _ := ParseFloat(Args[1], 4)
    d, _ := ParseFloat(Args[2], 4)
    s, _ := ParseFloat(Args[3], 4)
    r, _ := ParseFloat(Args[4], 4)

    z := [5][]float64{{0,0},{a,127},{a+d,s},{a+d+64,s},{a+d+64+r,0}}
    for i:=1;i<len(z);i++{
        v,w,x,y:=z[i-1][0],z[i-1][1],z[i][0],z[i][1]
        m:=(y-w)/(x-v)
        t:=y-m*x
        for v<=x{
            g.Set(int(Ceil(v)),127-int(Ceil(w)), c.RGBA{0,0,0,255})
            v+=.01
            w=m*v+t
        }
    }
    f,_:=Create("o.png")
    k.Encode(f,g)
}

@LuisMendo。默认情况下,0,0位于左上方。我会尽快使一切倒退。
kemicofa

1
我从来没有编码,所以我不知道。用户在此处手动查看其代码是因为与普通的压缩程序相比,它们可以节省更多的字节。这里欢迎不良的编码实践和技巧。例如,是否可以用变量(例如l1x,l1y,l1X,l1Y)代替struct对象?
seshoumara

1
@rugdealer ,如果您还没有看过的话,可能会有所帮助
Luis Mendo

1
多亏了您的链接@LuisMendo
kemicofa,

1
@rugdealer哇,好多了\ o /
Luis

1

直流电,120字节

最初,我以为我无法在dc中回答,但我看到允许打印矢量图像的语法。

?sR127r-sS[<svg><path d="M0 127 L]nrdn[ 0 L]n+dn32PlSn[ L]n64+dn32PlSn[ L]nlR+n[ 127" fill="none" stroke="red"/></svg>]p

该代码计算每个点的转换坐标,并为绘图生成SVG语法。由于图像编辑器的原点位于左上角,因此在这种情况下,我必须yheight127中减去值,以便显示图像时好像原点位于左下角。

运行示例:在线尝试!

dc -f plot_ADSR.dc <<< "15 30 70 40"

输出:

<svg><path d="M0 127 L15 0 L45 57 L109 57 L149 127" fill="none" stroke="red"/></svg>

要显示图像图,请将精确的输出保存到文件中,然后使用Gimp打开它,或者像上面一样在html页面中输入文本。

说明: dc是反向抛光ð ESK Ç alculator堆语言

该脚本是SVG语法字符串的长串。关键字M代表移动到坐标L代表画线从当前位置到给定坐标

?                           # read input (in reverse order by default). Stack: RSDA
sR                          # pop top value, store it in register 'R'. Stack: SDA
127r-sS                     # push 127, swap top 2 values, pop them and push
                            #subtracting result, save it to 'S', pop it. Stack: DA
[<svg><path d="M0 127 L]n   # [..]n print string (push then pop). Stack: unchanged
rdn                         # swap, duplicate top, print (A) and pop it. Stack: AD
[ 0 L]n                     # printing
+dn                         # pop top 2 values, push addition result, duplicate it,
                            #print and pop it. Stack: (A+D)
32P                         # print a space
lSn                         # push value from register 'S', print and pop it.
                            #Stack: unchanged
[ L]n                       # printing
64+dn                       # push 64, pop top 2 values, push addition result,
                            #duplicate it, print and pop it. Stack: (A+D+64)
32PlSn[ L]n                 # print space, print register 'S', more printing
lR+n                        #push value from register 'R', pop top 2 values, push
                            #addition result, print it and pop it. Stack: empty
[ 127" fill="none" stroke="red"/></svg>]p   # printing
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.