Attack, Decay, Sustain, Release


47

I sintetizzatori sonori usano i generatori di inviluppo per controllare come determinati parametri del suono (come il volume generale) cambiano nel tempo. In molti sintetizzatori un inviluppo è definito da quattro parametri, come rappresentato nella seguente figura da Wikipedia :

  • Tempo di attacco (A) : tempo impiegato dall'inviluppo a raggiungere il suo livello massimo, a partire da zero, alla prima pressione del tasto.
  • Decay time (D) : tempo impiegato dalla busta per raggiungere il livello di sustain specificato.
  • Livello di sustain (S) : livello che viene mantenuto, dopo l'attacco iniziale e il decadimento, per tutto il tempo in cui il tasto viene premuto.
  • Tempo di rilascio (R) : tempo impiegato dall'inviluppo a raggiungere lo zero quando si rilascia la chiave.

inserisci qui la descrizione dell'immagine

La sfida

Immettere i quattro parametri A, D, S, R e tracciare l'inviluppo .

I parametri saranno valori interi da 0 a 127 .

Si presume che il livello massimo (raggiunto alla fine della fase di attacco) sia 127 .

Si presume che il segmento orizzontale a livello di sustain abbia una durata 64 (nel suono effettivo questa durata non è fissa, ma è determinata dalla quantità di tempo in cui si tiene premuto il tasto).

Formato e ulteriori dettagli

L'output dovrebbe essere un'immagine in formato raster o vettoriale. Se è raster, la linea poligonale dovrebbe occupare almeno 50 pixel in verticale e in orizzontale.

L'immagine può essere visualizzata o prodotta come file in un formato immagine standard. Il file può essere scritto su disco o il suo esatto contenuto può essere emesso, su STDERR o come argomento di ritorno della funzione.

Il grafico deve contenere solo la linea poligonale che definisce la busta. La scala di ciascun asse può essere scelta liberamente. Altri elementi come linee degli assi, etichette numeriche o colori delle linee sono opzionali.

I mezzi di input e il formato sono flessibili come al solito. Ad esempio, puoi prendere i quattro numeri in qualsiasi ordine o un array che li contiene. È possibile fornire un programma o una funzione . Sono vietate le scappatoie standard .

Vince il codice più breve in byte.

Casi test

L'input è nel formato [A D S R]. Si noti che la scala è diversa in ogni figura (in conformità con la regola che la scala può essere scelta liberamente)

[15 30 70 40]

inserisci qui la descrizione dell'immagine

[64 64 64 64]

inserisci qui la descrizione dell'immagine

[0 10 50 80]

inserisci qui la descrizione dell'immagine

[0 0 90 80]

inserisci qui la descrizione dell'immagine

[5 50 0 0]

inserisci qui la descrizione dell'immagine

[5 50 0 80]

inserisci qui la descrizione dell'immagine

[24 32 127 48]

inserisci qui la descrizione dell'immagine


1
Mi aspettavo una sfida più simian dal titolo !
Ben

@Ben Anche quel riferimento era destinato :-) Adoro la privazione del sonno !
Luis Mendo,

Risposte:


7

MATL, 31 22 byte

Oii64ivYsO127itO5$h&XG

Accetta quattro ingressi separati ordinate come A, D, R,S

Provalo su MATL Online

Spiegazione

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

inserisci qui la descrizione dell'immagine


43

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

Grazie a David Carlisle per la sua utile risposta qui

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

Sì, hai sentito bene TikZ .

Spiegazione

Questo utilizza un paio di tecniche per raggiungere il suo obiettivo. La prima cosa è l'input. Molte persone potrebbero non sapere che L A T E X può ricevere input. Beh, può. Questo si ottiene con il comando \typein. Ciò interromperà il compilatore e richiederà l'input dell'utente mentre lo assegna a una variabile.

L'altra tecnica principale è l'uso di \def. \defa Tikz è assurdamente potente. In sostanza definisce un pezzo di codice e lo incolla ovunque tu chiami la variabile. In questo codice definiamo due cose in \typein[#1]{}modo da poter assegnare le nostre variabili da golf e )--(\a+\dperché questo codice si presenta un sacco di volte nella versione non controllata.

Ecco due versioni del codice (senza il 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);

Immagine:

Dato che non riesco a caricare un'immagine PDF direttamente e la sua conversione in qualsiasi altro formato sembra far scomparire del tutto la linea, ecco come potrebbe apparire un'immagine se aperta in Anteprima (l'input per questa immagine è [64 64 64 64]):

Anteprima immagine

Come puoi vedere è molto sottile. Tuttavia, poiché si tratta di un'immagine PDF e non di un'immagine raster, non è necessario rispettare i requisiti di spessore.


12
Ammiro sinceramente il fatto che tu conosca TikZ così bene che è la prima soluzione che ti viene in mente. (E se non lo fosse, è quello che ricorderà la leggenda)
Right Leg

1
Non input tikz\begin{document}funziona?
Fatalizza il

5
che ne dici di foto? 😉
Sarge Borsch,

Come lo rendi effettivamente? pdflatex adsr.texnon sembra funzionare. - Oh aspetta, funziona, non mi aspettavo che avrebbe richiesto un input interattivo!
cessò di girare in senso antiorario il

@WheatWizard imagemagick può convertire i PDF abbastanza bene se lo fai bene
Sarge Borsch

20

Python 2, 83 80 79 byte

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

Provalo online (versione a 83 byte, perché funziona online)

Nota che alcuni output potrebbero non essere completamente visibili usando Trinket, a causa del modo in cui funziona la tela. Dovrai scaricare e installare Python se vuoi che funzioni meglio.

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)

Questa versione non funziona in Trinket, poiché Trinket non supporta la decompressione del valore dell'input.


Puoi usare mapin 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 I get SuspensionError: Cannot call a function that blocks or suspends here on line undefined in main.pyon Trinket. Hai confermato che funziona? Non sono sicuro che l'errore sia univoco per Trinket o meno.
mbomb007,

Funziona per me nel 2.7.12.
xnor

@xnor Mmk, grazie. Probabilmente è una limitazione in Skulpt.
mbomb007,

Ho presentato una versione più semplice di questo programma come esempio al repository github di Skulpt, e hanno pensato che fosse una bella scoperta. Spero che saranno in grado di risolverlo, ma il ritmo del loro "sprint di tartarughe" sembra essere più di una passeggiata.
mbomb007,

17

Mathematica, 61 58 byte

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

è l'operatore per Transposeed è reso in apice Tda Mathematica.

Accetta gli argomenti nell'ordine S, R, A, De restituisce un oggetto grafico vettoriale.

Risultati per tutti e sette i casi di test:

inserisci qui la descrizione dell'immagine Clicca per una versione più grande.


È stato veloce!
Luis Mendo,

+1 per insegnarmi ListLinePlot:) E ce n'è anche uno ListStepPlotcosì utile!
Greg Martin,

12

R, 66 63 byte

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

Visualizza l'immagine, con i laboratori degli assi cumsum(c(0,A,D,64,R))e c(0,127,S,S,0), nonché le linee degli assi e le etichette numeriche.

Grazie a @Zahiro Mor per aver rasato 3 byte !

Risposta precedente:

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
puoi usare cumsum(c(0,A,D,64,R)) per sostituire il primo termine nella trama. con cumsum non avrai bisogno del trucco b e continuerai a radere 3 byte :) 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 byte

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

Ciò produce una funzione anonima "ans" che deve essere chiamata come 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>

Accetta uno alla volta nell'ordine A, S, D, R.


9

JavaScript (ES6), 114 111 byte

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>

Restituisce un'immagine SVG adatta per innerHTML. Aggiungi 18 byte per XML valido.


È fantastico il modo in cui la figura viene aggiornata in tempo reale!
Luis Mendo,

Questo è fantastico, dovrei imparare la sintassi SVG qualche volta. Forse aggiungere valori predefiniti alla <input>s?
ETHproductions

@ETHproductions Avevi in ​​mente impostazioni predefinite particolari? (Dato che l'impostazione predefinita in realtà non attiverà comunque il grafico iniziale ...)
Neil,

Stavo pensando forse solo 64,64,64,64. Normalmente codifico l'output corretto per l'input predefinito, ma vedo come sarebbe difficile qui ...
ETHproductions

8

Haskell, 112 110 byte

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]

Esempio di utilizzo: (0#10) 50 80.

busta adsr

Questo utilizza la Glosslibreria. La displayfunzione si aspetta che una finestra venga tracciata (qui: una finestra senza titolo ( ""), dimensioni 600x300, posizione (0,0)sul desktop), un colore di sfondo ( red) e un'immagine strega è una linea lungo il percorso creato comprimendo la somma cumulativa di [0,a,d,64,r]= [0,a,a+d,a+d+64,a+d+64+r]come coordinate x e [0,127,s,s,0]come coordinate y.

Modifica: Grazie @xnor per 2 byte!


Dovrebbe essere più breve per scriverescanl(+)0[a,d,64,r]
xnor

5

Elaborazione, 134 108 + 14 (chiamata a size) = 148 122 byte

Per prima cosa abbiamo bisogno di una chiamata da sizequalche parte nel programma in modo che l'output si adatti alla finestra (impostazione predefinita a 100x100).

size(400,400);

Ed ecco la vera funzione:

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

Chiamalo come f(15,20,70,40);

Immagine dello schermo

15, 20, 70, 40

Immagine


La mia risposta più recente è più semplice della risposta più vecchia, ma mi piace di più quella più vecchia (anche se è più grande).

Vecchia risposta (148 byte)

size(400,400);

e le due funzioni

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

Chiamalo come f(int_array_containing_values);e il risultato sarà simile a:f(new int[]{15,20,70,40});


4

SmileBASIC, 90 byte

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, 149 130 byte

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

accetta input dagli argomenti della riga di comando, scrive l'immagine (PNG con il grafico blu su nero) su stdout. Richiede PHP 7.1 o successivo.

utilizzo es

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

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

+4 byte per PHP precedente: sostituisci [,$a,$d,$s,$r]con list(,$a,$d,$s,$r).


C'è un piccolo trucco lì dentro: invece di usare imageopenpolygonper nascondere la linea di base, la linea del poligono di finitura viene disegnata all'esterno dell'area di disegno. (y = 127 verrebbe visualizzato solo su un'immagine con altezza> = 128.)

Avrei potuto risparmiare di più con il colore 99 o 9 anziché 999; ma quelli sono piuttosto difficili da vedere sul nero. :)


3

Bash + grace , 70 byte

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

Lo script scrive per archiviare fle coordinate di ciascun punto e xmgrace (la versione della GUI) legge il file e visualizza il grafico usando le linee per impostazione predefinita.

Esegui :

./plot_ADSR.sh 15 30 70 40

Output: (schermata di stampa)

15 30 70 40

Penso che questo possa essere fatto direttamente da uno script di grazia, se può accettare input, ma non ho familiarità con la sua sintassi. Ci penserò.

Spiegazione:

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

Vai, 947 915 506 byte

Questo è tutt'altro che ottimizzato, cercando di imparare la lingua mentre partecipi a queste domande. Sentiti libero di sottolineare cosa posso fare.

immagine fissa

Condensato:

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

@LuisMendo lo è. Di default 0,0 è in alto a sinistra. Ill inverso tutto appena posso.
kemicofa,

1
Non ho mai programmato, quindi non lo so. Gli utenti qui golfano il loro codice manualmente perché possono salvare più byte di un minificatore generale. Qui sono ben accette pratiche e trucchi per la codifica. Ad esempio, sostituire gli oggetti struct con variabili (come l1x, l1y, l1X, l1Y) sarebbe forse più golfista?
seshoumara,

1
@rugdealer Questo potrebbe aiutare, nel caso in cui non l'avessi visto
Luis Mendo,

1
Perso quasi 400 byte grazie al tuo link @LuisMendo
kemicofa,

1
@rugdealer Wow, questo è molto \ o /
Luis Mendo il

1

dc, 120 byte

Inizialmente pensavo di non poter rispondere in cc, ma vedo che è consentita la stampa della sintassi di un'immagine vettoriale.

?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

Il codice calcola le coordinate tradotte di ciascun punto e genera la sintassi SVG per il grafico. Poiché un editor di immagini ha l'origine nell'angolo in alto a sinistra, ho dovuto sottrarre i yvalori da height, 127 in questo caso, in modo che l'immagine sia mostrata come se l'origine fosse nell'angolo in basso a sinistra.

Esegui esempio: o provalo online!

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

Produzione:

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

Per visualizzare la trama dell'immagine, salva l'output esatto in un file e aprilo con Gimp, ad esempio, oppure inserisci il testo in una pagina html come ho fatto sopra.

Spiegazione: dc è un reverse-polacco D ESK c alculator lingua pila

Lo script è una lunga concatenazione della stringa di sintassi SVG. La parola chiave Mindica lo spostamento verso le coordinate e Lindica la linea di disegno dalla posizione corrente a quella data .

?                           # 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.