Attaque, Déclin, Maintien, Libération

47

Les synthétiseurs sonores utilisent des générateurs d'enveloppe pour contrôler la manière dont certains paramètres du son (tels que le volume général) changent avec le temps. Dans de nombreux synthétiseurs, une enveloppe est définie par quatre paramètres, comme indiqué dans la figure suivante de Wikipedia :

  • Temps d'attaque (A) : temps nécessaire pour que l'enveloppe atteigne son niveau maximum, à partir de zéro, lorsque la touche est enfoncée pour la première fois.
  • Temps de chute (D) : temps mis par l'enveloppe pour atteindre le niveau de maintien spécifié.
  • Sustain level (S) : niveau qui est maintenu, après l'attaque initiale et la décroissance, tant que la touche est enfoncée.
  • Temps de relâchement (R) : temps nécessaire pour que l’enveloppe atteigne zéro lorsque la touche est relâchée.

entrez la description de l'image ici

Le défi

Entrez les quatre paramètres A, D, S, R et tracez l'enveloppe .

Les paramètres seront des valeurs entières comprises entre 0 et 127 .

Le niveau maximum (atteint à la fin de la phase d’attaque) sera de 127 .

La durée du segment horizontal au niveau de l'effet Sustain sera supposée être de 64 (dans le son réel, cette durée n'est pas fixée, elle est déterminée par la durée pendant laquelle la touche est enfoncée).

Format et détails supplémentaires

La sortie doit être une image au format raster ou vectoriel. Si c'est un raster, la ligne polygonale doit occuper au moins 50 pixels verticalement et horizontalement.

L'image peut être affichée ou produite sous forme de fichier dans un format d'image standard. Le fichier peut être écrit sur le disque ou son contenu exact peut être exporté soit dans STDERR, soit en tant qu'argument de retour de fonction.

Le graphique doit uniquement contenir la ligne polygonale qui définit l'enveloppe. L'échelle de chaque axe peut être choisie librement. D'autres éléments tels que des lignes d'axe, des étiquettes numériques ou des couleurs de ligne sont facultatifs.

Les moyens d'entrée et le format sont flexibles comme d'habitude. Par exemple, vous pouvez prendre les quatre nombres dans n'importe quel ordre ou un tableau les contenant. Un programme ou une fonction peut être fourni. Les failles standard sont interdites.

Le code le plus court en octets gagne.

Cas de test

L'entrée est dans le format [A D S R]. Notez que l'échelle est différente dans chaque figure (conformément à la règle selon laquelle l'échelle peut être choisie librement)

[15 30 70 40]

entrez la description de l'image ici

[64 64 64 64]

entrez la description de l'image ici

[0 10 50 80]

entrez la description de l'image ici

[0 0 90 80]

entrez la description de l'image ici

[5 50 0 0]

entrez la description de l'image ici

[5 50 0 80]

entrez la description de l'image ici

[24 32 127 48]

entrez la description de l'image ici

Luis Mendo
la source
1
Je m'attendais à un défi plus simien du titre !
Ben
@Ben Cette référence était aussi destinée :-) J'aime la privation de sommeil !
Luis Mendo

Réponses:

7

MATL, 31 22 octets

Oii64ivYsO127itO5$h&XG

Accepte quatre entrées distinctes commandées en A, D, R,S

Essayez-le sur MATL Online

Explication

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

entrez la description de l'image ici

Suever
la source
43

TikZ, 195 193 181 177 172 167 163 160 160 159 octets

Merci à David Carlisle pour sa réponse utile ici

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

Oui, vous avez bien entendu TikZ .

Explication

Cela utilise quelques techniques pour atteindre son objectif. La première chose est l'entrée. La plupart des gens ne savent peut-être pas que L A T E X peut prendre des contributions. Eh bien ça peut. Ceci est réalisé avec la commande \typein. Cela arrêtera le compilateur et demandera une entrée à l'utilisateur en l'affectant à une variable.

L'autre technique principale est l'utilisation de \def. \defdans Tikz est absurdement puissant. Il définit essentiellement un morceau de code et le colle partout où vous appelez la variable. Dans ce code, nous définissons deux choses \typein[#1]{}pour pouvoir affecter nos variables de manière amusante et )--(\a+\dparce que ce code apparaît plusieurs fois dans la version non-golfée.

Voici deux versions du code (sans le wrapper):

Golfé:

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

Étant donné que je ne peux pas télécharger directement une image pdf et que la convertir en un autre format semble entraîner la disparition complète de la ligne, voici à quoi une image pourrait ressembler lorsqu'elle est ouverte dans Aperçu (l'entrée est pour cette image [64 64 64 64]):

Aperçu de l'image

Comme vous pouvez le voir, c'est très mince. Cependant, étant donné qu’il s’agit d’une image PDF et non d’une image raster, il n’est pas nécessaire de respecter les exigences d’épaisseur.

Assistant de blé
la source
12
J'admire sincèrement le fait que vous connaissez si bien TikZ que c'est la première solution qui vous vient à l'esprit. (Et si ce n'était pas le cas, c'est ce dont la légende se souviendra.)
jambe droite
1
Ça ne input tikz\begin{document}marche pas ?
Fataliser
5
que diriez-vous des photos? 😉
Sarge Borsch
Comment rendez-vous réellement cela? pdflatex adsr.texne semble pas fonctionner. - Oh, attends, ça marche, je ne m'attendais pas à ce que cela demande une entrée interactive!
cessé de tourner dans le sens anti-horaire le
@WheatWizard imagemagick peut convertir les fichiers PDF de manière raisonnable si vous le faites correctement
Sarge Borsch
20

Python 2, 83 80 79 octets

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])

Essayez-le en ligne (version de 83 octets, car il fonctionne en ligne)

Notez que certaines sorties peuvent ne pas être complètement visibles à l'aide de Trinket, en raison du fonctionnement du canevas. Vous devrez télécharger et installer Python si vous voulez que cela fonctionne mieux.

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)

Cette version ne fonctionne pas dans Trinket, car Trinket ne prend pas en charge la valeur de décompression des entrées.

mbomb007
la source
Vous pouvez utiliser mapdans 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 je monte SuspensionError: Cannot call a function that blocks or suspends here on line undefined in main.pysur bibelot Avez-vous confirmé que cela fonctionne? Je ne sais pas si l'erreur est propre à Trinket ou non.
mbomb007
Fonctionne pour moi dans 2.7.12.
XNOR
@xnor Mmk, merci. C'est probablement une limitation dans Skulpt.
mbomb007
J'ai soumis une version plus simple de ce programme à titre d'exemple au dépôt Skulpt github, et ils ont pensé que c'était une belle découverte. J'espère qu'ils pourront y remédier, mais le rythme de leur «sprint de tortue» semble être plus une marche.
mbomb007
17

Mathematica, 61 58 octets

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

est l'opérateur Transposeet est rendu en exposant Tpar Mathematica.

Prend les arguments dans l'ordre S, R, A, Det retourne un objet graphique vectoriel.

Résultats pour les sept cas de test:

entrez la description de l'image ici Cliquez pour agrandir.

Martin Ender
la source
C'était rapide!
Luis Mendo
+1 pour m'enseigner ListLinePlot:) Et il y en a un ListStepPlotaussi - si utile!
Greg Martin
12

R, 66 63 octets

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

Affiche l'image, les laboratoires d'axes étant cumsum(c(0,A,D,64,R))et c(0,127,S,S,0), ainsi que les lignes d'axe et les étiquettes numériques.

Merci à @Zahiro Mor d'avoir réduit de 3 octets !

Réponse précédente:

function(A,D,S,R)plot(c(0,A,A+D,b<-A+D+64,b+R),c(0,127,S,S,0),"l")
Frédéric
la source
2
vous pouvez utiliser cumsum(c(0,A,D,64,R)) pour remplacer le premier terme du graphique. avec cumsum vous n'aurez pas besoin de la ruse b et vous aurez encore 3 function(A,D,S,R)plot(cumsum(c(0,A,D,64,R)),c(0,127,S,S,0),"l")
rasages
11

Matlab, 50 octets

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

Cela donne une fonction anonyme "ans" qui doit être appelée comme ans (A, D, S, R).

Lukas K.
la source
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>

Prend une entrée à la fois dans l'ordre A, S, D, R.

ETHproductions
la source
9

JavaScript (ES6), 114 111 octets

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>

Renvoie une image SVG appropriée pour innerHTML. Ajoutez 18 octets pour un code XML valide.

Neil
la source
C'est génial de voir comment la figure est mise à jour en temps réel!
Luis Mendo
C'est génial, je devrais apprendre la syntaxe SVG de temps en temps. Peut-être ajouter des valeurs par défaut au <input>s?
ETHproductions
@ETHproductions Avez-vous eu à l'esprit des défauts particuliers? (Etant donné que les réglages par défaut ne déclencheront pas le graphique initial de toute façon ...)
Neil
Je pensais peut-être juste 64,64,64,64. Normalement, je coderais correctement la sortie correcte pour l'entrée par défaut, mais je vois à quel point ce serait difficile ici ...
ETHproductions
8

Haskell, 112 110 octets

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]

Exemple d'utilisation: (0#10) 50 80.

enveloppe adsr

Cela utilise la Glossbibliothèque. La displayfonction attend une fenêtre dans laquelle tracer (ici: une fenêtre sans titre ( ""), taille 600x300, position (0,0)sur le bureau), une couleur de fond ( red) et une image qui est une ligne le long du chemin créé en zippant la somme cumulée de [0,a,d,64,r]= [0,a,a+d,a+d+64,a+d+64+r]comme le coordonnées x et [0,127,s,s,0]comme les coordonnées y.

Edit: Merci @xnor pour 2 octets!

nimi
la source
Devrait être plus court pour écrirescanl(+)0[a,d,64,r]
xnor
5

Traitement, 134 108 + 14 (appel à size) = 148 122 octets

Nous avons d’abord besoin d’un appel sizequelque part dans le programme pour que la sortie tienne dans la fenêtre (valeur par défaut de 100x100).

size(400,400);

Et voici la fonction réelle:

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);}

Appelez ça comme f(15,20,70,40);

Capture d'écran

15, 20, 70, 40

image


Ma réponse la plus récente est plus simple que la réponse plus ancienne, mais j'aime davantage la réponse la plus ancienne (même si elle est plus grande).

Ancienne réponse (148 octets)

size(400,400);

et les deux fonctions

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);}

Appelez-le comme f(int_array_containing_values);et le résultat ressemblera à quelque chose comme:f(new int[]{15,20,70,40});

Kritixi Lithos
la source
4

SmileBASIC, 90 octets

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
12Me21
la source
4

PHP, 149 à 130 octets

[,$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);

prend les arguments de la ligne de commande, écrit l'image (PNG avec le graphe bleu sur noir) sur la sortie standard. Nécessite PHP 7.1 ou une version ultérieure.

utilisation par exemple

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

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

+4 octets pour les anciens PHP: Remplacez [,$a,$d,$s,$r]par list(,$a,$d,$s,$r).


Il y a un petit hack dedans: au lieu d'utiliser imageopenpolygonpour masquer la ligne de base, la ligne de polygone de finition est dessinée à l'extérieur du canevas. (y = 127 ne s'afficherait que sur une image de hauteur> = 128.)

J'aurais pu économiser plus avec la couleur 99 ou 9 au lieu de 999; mais ceux-ci sont assez difficiles à voir en noir. :)

Titus
la source
3

Bash + Grace , 70 octets

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

Le script écrit pour farchiver les coordonnées de chaque point et xmgrace (la version de l'interface graphique) lit le fichier et affiche le tracé en utilisant des lignes par défaut.

Run :

./plot_ADSR.sh 15 30 70 40

Sortie: (écran d'impression)

15 30 70 40

Je pense que cela peut être fait directement par un script de grâce, s'il accepte les entrées, mais je ne connais pas bien sa syntaxe. Je vais y regarder.

Explication:

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
seshoumara
la source
2

Go, 947 915 506 octets

C'est loin d'être optimisé, essayer d'apprendre la langue tout en participant à ces questions. N'hésitez pas à préciser ce que je peux faire.

image fixe

Condensé:

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

Sans condition:

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)
}
kemicofa soutient Monica
la source
@ LuisMendo c'est. Par défaut, 0,0 est en haut à gauche. Ill inverse tout dès que je peux.
kemicofa soutient Monica le
1
Je n'ai jamais codé go, donc je ne sais pas. Les utilisateurs ici golfent leur code manuellement car ils peuvent économiser plus d'octets qu'un minifier général. Les mauvaises pratiques et astuces de codage sont les bienvenues ici. Par exemple, remplacer les objets struct par des variables (comme l1x, l1y, l1X, l1Y) ne serait-il pas plus golfeur?
Seshoumara
1
@rugdealer Cela peut aider, au cas où vous ne l'auriez pas vu
Luis Mendo
1
Perdu près de 400 octets grâce à votre lien @LuisMendo
kemicofa soutient Monica 17/02/2017
1
@rugdealer Wow, c'est beaucoup \ o /
Luis Mendo
1

dc, 120 octets

Au départ, je pensais que je ne pouvais pas répondre en courant continu, mais je constate que l’impression de la syntaxe d’une image vectorielle est autorisée.

?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

Le code calcule les coordonnées traduites de chaque point et génère la syntaxe SVG du tracé. Comme un éditeur d'image a son origine dans le coin supérieur gauche, il a fallu soustraire les yvaleurs de height127, dans ce cas, pour que l'image soit affichée comme si l'origine était dans le coin inférieur gauche.

Exécuter un exemple: ou l' essayer en ligne!

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

Sortie:

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

Pour afficher le tracé de l'image, enregistrez cette sortie exacte dans un fichier et ouvrez-le avec Gimp, par exemple, ou entrez le texte dans une page HTML comme je l'ai fait ci-dessus.

Explication: dc est un inverse de polissage d esk c alculator langue de la pile

Le script est une longue concaténation de la chaîne de syntaxe SVG. Le mot - clé Mest synonyme de mouvement pour coordonner et Lreprésente la ligne de tirage au sort de la position actuelle de coordonnées données .

?                           # 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
seshoumara
la source