[Question]
  [
[Sound synthesizers](https://en.wikipedia.org/wiki/Synthesizer) use envelope generators to control how certain parameters of the sound (such as overall loudness) change with time. In many synthesizers an envelope is defined by four parameters, as represented in the following figure from [Wikipedia](https://en.wikipedia.org/wiki/Synthesizer#Attack_Decay_Sustain_Release_.28ADSR.29_envelope):
* **Attack time (A)**: time taken for the envelope to reach its maximum level, starting from zero, when the key is first pressed.
* **Decay time (D)**: time taken for the envelope to reach the specified sustain level.
* **Sustain level (S)**: level which is maintained, after the initial attack and decay, for as long as the key is being pressed.
* **Release time (R)**: time taken for the envelope to reach zero when the key is released.
[![enter image description here](https://i.stack.imgur.com/lazZO.png)](https://i.stack.imgur.com/lazZO.png)
# The challenge
Input the four parameters A, D, S, R and **plot the envelope**.
Parameters will be **integer values from 0 to 127**.
The **maximum level** (reached at the end of the attack phase) will be assumed to be **127**.
The **horizontal segment at the sustain level** will be assumed to have **duration 64** (in the actual sound this duration is not fixed, but is determined by the amount of time that the key is held).
# Format and further details
The output should be an image in raster or vector format. If it's raster, the polygonal line should occupy at least 50 pixels vertically an horizontally.
The image can be either displayed or produced as a file in a standard image format. The file can be written to disk, or its exact contents can be output, either to STDERR or as function return argument.
The graph need only contain the polygonal line that defines the envelope. The scale of each axis can be freely chosen. Other elements such as axis lines, numeric labels or line colors are optional.
Input means and format are [flexible](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods) as usual. For example, you can take the four numbers in any order, or an array containing them. [A program or a function](https://codegolf.meta.stackexchange.com/questions/2419/default-for-code-golf-program-function-or-snippet) can be provided. [Standard loopholes](https://codegolf.meta.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) are forbidden.
Shortest code in bytes wins.
# Test cases
Input is in the format `[A D S R]`. Note that the scale is different in each figure (in accordance with the rule that scale can be freely chosen)
```
[15 30 70 40]
```
[![enter image description here](https://i.stack.imgur.com/9dSO4.png)](https://i.stack.imgur.com/9dSO4.png)
```
[64 64 64 64]
```
[![enter image description here](https://i.stack.imgur.com/s5012.png)](https://i.stack.imgur.com/s5012.png)
```
[0 10 50 80]
```
[![enter image description here](https://i.stack.imgur.com/9e6jE.png)](https://i.stack.imgur.com/9e6jE.png)
```
[0 0 90 80]
```
[![enter image description here](https://i.stack.imgur.com/kOo4E.png)](https://i.stack.imgur.com/kOo4E.png)
```
[5 50 0 0]
```
[![enter image description here](https://i.stack.imgur.com/u8fnH.png)](https://i.stack.imgur.com/u8fnH.png)
```
[5 50 0 80]
```
[![enter image description here](https://i.stack.imgur.com/C5SW5.png)](https://i.stack.imgur.com/C5SW5.png)
```
[24 32 127 48]
```
[![enter image description here](https://i.stack.imgur.com/vY3Sp.png)](https://i.stack.imgur.com/vY3Sp.png)
  
[Answer]
# TikZ, ~~195~~ ~~193~~ ~~181~~ ~~177~~ ~~172~~ ~~167~~ ~~163~~ ~~160~~ 159 bytes
*Thanks to David Carlisle for his helpful answer [here](https://tex.stackexchange.com/a/372621/124071)*
```
\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}
```
Yes, you heard right ***TikZ***.
## Explanation
This uses a couple of techniques to achieve its goal. The first thing is input. Most people might not know that LATEX can take input. Well it can. This is achieved with the command `\typein`. This will halt the compiler and request input from the user as assign it to a variable.
The other main technique is the use of `\def`. `\def` in Tikz is absurdly powerful. It essentially defines a piece of code and pastes it everywhere you call the variable. In this code we define two things `\typein[#1]{}` so that we can assign our variables golfily and `)--(\a+\d` because this code shows up a bunch of times in the ungolfed version.
Here are two versions of the code (without the wrapper):
### Golfed:
```
\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}
```
### Ungolfed:
```
\typein[\a]{}\typein[\s]{}\typein[\d]{}\typein[\r]{}\draw(0,0)--(\a,127)--(\a+\d,)--(\a+\d+64,)--(\a+\d+\r+64,0);
```
## Image:
Since I cannot upload a pdf image directly, and converting it to any other format seems to cause the line to disappear altogether, here is what an image might look like when opened in Preview (input for this image is `[64 64 64 64]`):
[![Preview image](https://i.stack.imgur.com/yfCMN.png)](https://i.stack.imgur.com/yfCMN.png)
As you can see it is very thin. However because it is a PDF image and not a raster image does not have to comply with thickness requirements.
[Answer]
# Python 2, ~~83~~ ~~80~~ 79 bytes
```
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])
```
[**Try it online**](https://trinket.io/python/874e164de0) (83-byte version, because it runs online)
Note that certain outputs may not be completely visible using Trinket, because of the way the canvas works. You'll need to download and install Python if you want it to work better.
### Ungolfed:
```
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)
```
This version doesn't work in Trinket, because Trinket doesn't support value unpacking of input.
[Answer]
## Mathematica, ~~61~~ 58 bytes
```
ListLinePlot[{Accumulate@{0,##3,64,#2},{0,127,#,#,0}}Ôèá]&
```
`Ôèá` is the operator for `Transpose` and is rendered as a superscript `T` by Mathematica.
Takes the arguments in the order `S, R, A, D` and returns a vector graphics object.
Results for all seven test cases:
[![enter image description here](https://i.stack.imgur.com/2uVkO.png)](https://i.stack.imgur.com/2uVkO.png)
Click for larger version.
[Answer]
## R, ~~66~~ 63 bytes
```
function(A,D,S,R)plot(cumsum(c(0,A,D,64,R)),c(0,127,S,S,0),"l")
```
Displays the image, with axis labs being `cumsum(c(0,A,D,64,R))` and `c(0,127,S,S,0)`, as well axis lines and numeric labels.
Thanks to @Zahiro Mor for shaving off *3 bytes* !
**Previous answer :**
```
function(A,D,S,R)plot(c(0,A,A+D,b<-A+D+64,b+R),c(0,127,S,S,0),"l")
```
[Answer]
# Matlab, 50 bytes
```
@(A,D,S,R)plot(cumsum([0,A,D,64,R]),[0,127,S,S,0])
```
This yields an anonymous function "ans" that has to be called as ans(A,D,S,R).
[Answer]
## 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>
```
Takes input one at a time in the order `A, S, D, R`.
[Answer]
## JavaScript (ES6), ~~114~~ 111 bytes
```
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>
```
Returns an SVG image suitable for `innerHTML`. Add 18 bytes for valid XML.
[Answer]
## Haskell, ~~112~~ 110 bytes
```
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]
```
Usage example: `(0#10) 50 80`.
![adsr envelope](https://i.stack.imgur.com/SRogC.png)
This uses the `Gloss` library. The `display` function expects a window to plot in (here: a window without title (`""`), size 600x300, position `(0,0)` on desktop), a background color (`red`) and picture witch is a line along the path made by zipping the cumulative sum of `[0,a,d,64,r]` = `[0,a,a+d,a+d+64,a+d+64+r]` as the x coordinates and `[0,127,s,s,0]` as the y coordinates. 
Edit: Thanks @xnor for 2 bytes! 
[Answer]
# MATL, ~~31~~ 22 bytes
```
Oii64ivYsO127itO5$h&XG
```
Accepts four separate inputs ordered as `A`, `D`, `R`, `S`
Try it out at [**MATL Online**](https://matl.io/?code=Oii64ivYsO127itO5%24h%26XG&inputs=15%0A30%0A40%0A70&version=19.7.4)
**Explanation**
```
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
```
[![enter image description here](https://i.stack.imgur.com/IhOl1.png)](https://i.stack.imgur.com/IhOl1.png)
[Answer]
# Processing, ~~134~~ 108 + 14(call to `size`) = ~~148~~ 122 bytes
First we need a call to `size` somewhere in the program so that the output will fit in the window (default at 100x100).
```
size(400,400);
```
And here's the actual function:
```
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);}
```
Call it like `f(15,20,70,40);`
### Screenshot
```
15, 20, 70, 40
```
[![image](https://i.stack.imgur.com/pBwtR.png)](https://i.stack.imgur.com/pBwtR.png)
---
My newer answer is more straightforward than the older answer, but I like the older one more (even if it is bigger).
### Old answer (148 bytes)
```
size(400,400);
```
and the two functions
```
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);}
```
Call it like `f(int_array_containing_values);` and the result will look something like: `f(new int[]{15,20,70,40});`
[Answer]
# SmileBASIC, 90 bytes
```
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
```
[Answer]
# PHP, ~~149~~ 130 bytes
```
[,$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);
```
takes input from command line arguments, writes image (PNG with graph blue on black) to stdout. Requires PHP 7.1 or later.
usage e.g.
```
# any OS with ImageMagick:
php -r '<code>' <parameters> | display
# linux with feh:
php -r '<code>' <parameters> | feh
```
+4 bytes for older PHP: Replace `[,$a,$d,$s,$r]` with `list(,$a,$d,$s,$r)`.
---
There is a small hack in there: instead of using `imageopenpolygon` to hide the base line, the finishing polygon line is drawn outside the canvas. (y=127 would only display on an image with height >= 128.)
I could have saved more with color 99 or 9 instead of 999; but those are pretty hard to see on black. :)
[Answer]
## Bash + [grace](https://en.wikipedia.org/wiki/Grace_(plotting_tool)), 70 bytes
```
t=$[$1+$2]
echo "0 0
$1 127
$t $3
$[t+64] $3
$[t+64+$4] 0">f
xmgrace f
```
The script writes to file `f` the coordinates of each point, and xmgrace (the GUI version) reads the file and displays the plot using lines by default.
**Run**:
```
./plot_ADSR.sh 15 30 70 40
```
**Output:** (print screen)
[![15 30 70 40](https://i.stack.imgur.com/O6X3f.png)](https://i.stack.imgur.com/O6X3f.png)
I think this can be done directly by a grace script, if it can accept input, but I'm not familiar with its syntax. I'll look into it.
**Explanation:**
```
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
```
[Answer]
## Go, ~~947~~ ~~915~~ 506 bytes
*This is far from optimized, trying to learn the language while participating in these questions. Feel free to point out what I can do.*
[![fixed image](https://i.stack.imgur.com/rX1ki.png)](https://i.stack.imgur.com/rX1ki.png)
**Condensed:**
```
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)}
```
**Uncondenced:**
```
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)
}
```
[Answer]
## dc, 120 bytes
Initially I thought I can't answer in dc, but I see that printing the syntax of a vector image is allowed.
```
?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
```
The code calculates the translated coordinates of each point and generates the SVG syntax for the plot. Since an image editor has the origin at the top-left corner, I had to subtract the `y` values from `height`, 127 in this case, so that the image is shown as if the origin is at the bottom-left corner.
**Run example:** or [**Try it Online!**](https://tio.run/nexus/dc#@29fHGRoZF6kWxwcbVNclm5nU5BYkqGQYqvka6AAlFDwic0rSsmLVjAAsbRT8oyNAnKCgXwgz8wElZ8TpA1kADUpKaRl5uTYKuXl56UqKRSXFOVnp9oqFaWmKOnb2eiDbIkt@P/f0FTB2EDB3EDBxAAA)
```
dc -f plot_ADSR.dc <<< "15 30 70 40"
```
**Output:**
```
<svg><path d="M0 127 L15 0 L45 57 L109 57 L149 127" fill="none" stroke="red"/></svg>
```
To display the image plot, save that exact output to a file and open it with Gimp, for example, or enter the text in an html page as I did above.
**Explanation:** `dc` is a reverse-polish **d**esk **c**alculator stack language
The script is a long concatenation of the SVG syntax string. The keyword `M` stands for *move to coordinate* and `L` stands for *draw line from current position to given coordinate*.
```
?                           # 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
```
[Answer]
# Processing, 111 bytes
```
size(400,128);line(0,127,a,0),line(a,0,a+d,127-s),line(a+d,127-s,a+d+64,127-s),line(a+d+64,127-s,a+d+64+r,127);
```
Used a simpler method of input compared to user41805.
## Output (formatted)
`0,0,90,80`
[![enter image description here](https://i.stack.imgur.com/VjKEi.png)](https://i.stack.imgur.com/VjKEi.png)
`0,10,50,80`
[![enter image description here](https://i.stack.imgur.com/DpJsj.png)](https://i.stack.imgur.com/DpJsj.png)
`5,50,0,0`
[![enter image description here](https://i.stack.imgur.com/rNPTl.png)](https://i.stack.imgur.com/rNPTl.png)
`5,50,0,80`
[![enter image description here](https://i.stack.imgur.com/1woH3.png)](https://i.stack.imgur.com/1woH3.png)
`15,30,70,40`
[![enter image description here](https://i.stack.imgur.com/BTFrn.png)](https://i.stack.imgur.com/BTFrn.png)
`24,32,127,48`
[![enter image description here](https://i.stack.imgur.com/xVFYC.png)](https://i.stack.imgur.com/xVFYC.png)
`64,64,64,64`
[![enter image description here](https://i.stack.imgur.com/3F5kW.png)](https://i.stack.imgur.com/3F5kW.png)
## Ungolfed code with formatting
```
void settings() {
  //size adjusts according to params
  size(a+d+64+r, 129);
}
void setup() {
  translate(1,0);
  background(255); 
  strokeWeight(3);
  
  //axes
  line(0,127,600,127);
  line(0,0,0,127);
  
  //graph
  stroke(53,113,9);
  line(0,127,a,0);
  stroke(228,77,40);
  line(a,0,a+d,127-s);
  stroke(26,39,232);
  line(a+d,127-s,a+d+64,127-s);
  stroke(110,27,109);
  line(a+d+64,127-s,a+d+64+r,127);
  
  //save to file
  save("a"+a+"d"+d+"s"+s+"r"+r+".png");
}
int a=24,d=32,s=127,r=48;
```
This program will save your images to disk in the same folder.
]