Jogi Release Time | Jogi Netflix Release Time |Jogi Movie Release Time | Jogi Review |Diljit Dosanjh
Jogi Release Time | Jogi Netflix Release Time |Jogi Movie Release Time | Jogi Review |Diljit Dosanjh
Hello Dosto Webmovie me apka welcome hai ,
Jogi Release Time
Jogi Netflix Release Time
Jogi Movie Release Time
Jogi Netflix Movie Release Time
Jogi Review
Jogi Movie Review
Diljit Dosanjh
#Jogi
#JogiReview
#netflix
#diljitdosanjh
#releasetime
source
Ein bisschen früher, als auf Facebook, die dritte Sneak-Preview zur #setrouver #EP - a game called love // #sneakpreview #inthestudio #kopfkinomusik #apl #aproducerslife #elektronischemusik #einProduzentenleben #einbisschenschweben #TEASER #kreativfabrik #bassistliebe #tinder #gedankenimquadrat #electronica #house #electronica #elektronischetanzmusik #einProduzentenleben #träumelebenleben #releasetime #agamecalledlove
July 2000- In addition to the light blue N64 variant, the coveted orange variant also released exclusively in Japan. The orange N64 is rarer than the light blue, but only slightly. (At the Releasetime) It is estimated that between 100,000 and 1,000,000 of this variation were made. These are very few copies if you compare them with the quantities of the following generations of special editions. Just like the brothers, it has the Pikachu extras- The Pikachu's foot is the rest button, the Pokeball is the on/off button, and when it's on, Pikachu's cheeks light up. _______________________________ #pokemon #pokémon #pokemonlove #pokemonlife #pikachun64 #n64 #nintendo64 #nintendo #nintendolife #nintendopokemon #nintendocollection #nintendopokemon #pokemon25th #pikachu #consolecollection #retroconsole #pokemonlover #pokemoncompany #pokeball #pokemonhistory #pokemondeutschland #pokemon2000 #pokemonjapan #nintendofan #pikachu #pokemoncollection #pokémoncollection #pokecollector #pokéball #consolecollection #videogamecollection #pokemonart (hier: Kanto Region) https://www.instagram.com/p/CXjnEXeodlI/?utm_medium=tumblr
Instructions for use. 1. Turn your computer volume all the way down. 2. Put on headphones. 3. Carefully raise the volume. 4. Enjoy at a comfortable listening level.
Do not: turn volume all the way up, use headphones, experience bloody headphones.
*/
About to record a video on processing using my lamp to create visuals well as control an audio visual patch that through Arduino, generates a melodic rythm and affects the video and lamp visuals being recorded.
This is the code I used to enables the webcam to work, Arduino to input light data, and generate sound as well as visuals.
Initially, I attempted to learn how to utilise motion to generate the sound however, it turned out to be more difficult than expected.
-------------------------------
import processing.video.*;
import processing.sound.*;
//int circleX = 50;
Arduino arduino; // create a variable arduino of the Arduino data type
SawOsc saw;
Env env;
import processing.serial.*; // reference the serial library
import cc.arduino.*; // reference the arduino library
Utilizzo di lookup table come generatore d’onda quadra limitata in banda al posto di un oscillatore sinusoidale.
Utilizzo della struttura di controllo “for”.
PREREQUISITI
Per poter utilizzare questo programma serve avere un controller MIDI connesso al computer, o una virtual MIDI keyboard. Questo va connesso (o aperto nel caso di una tastiera virtuale), prima di far partire il programma.
Conoscenza base del protocollo MIDI (https://it.wikipedia.org/wiki/Musical_Instrument_Digital_Interface - http://www.nyu.edu/classes/bello/FMT_files/8_MIDIcomms.pdf - https://www.nyu.edu/classes/bello/FMT_files/9_MIDI_code.pdf)
Conoscenza base della sintesi additiva e della serie di Fourier
LOOKUP TABLE E PHASOR
Nei precedenti tutorial sono stati affrontate principalmente problematiche riguardanti il controllo delle varie componenti base di un sintetizzatore (implementazione di una tastiera MIDI, controllo in frequenza di un oscillatore, portamento, etc.). Questo tutorial invece, sara’ incentrato sull’implementazione di un oscillatore ad onda quadra limitato in banda e si iniziera’ ad affrontare la parte riguardante il timbro dello strumento.
Generalmente I sintetizzatori hardware hanno una sezione chiamata VCO (voltage controlled oscillators - se analogici) o DCO (digital controlled oscillators - se digitali), la quale include vari oscillatori con forme d’onda differenti tra loro.
Le forme d’onde classiche molto spesso implementate nei synth hardware e software sono: sinusoidale, quadra, triangolare e dente di sega.
Esistono vari modi per implementare questi generatori in ChucK, il piu’ semplice prevede l’utilizzo di dedicati UGen come SqrOsc, TriOsc e SawOsc (onda quadra, triangolare e dente di sega), I quali hanno le stesse funzionalita’ dell’UGen SinOsc con cui si e’ lavorato fin’ora.
Purtroppo pero’, non e’ sempre possibile utilizzare questi UGen, in quanto e’ molto facile imbattersi in una problematica comune a tutti I sistemi digitali: l’aliasing.
Gli UGen presenti in ChucK, generano una versione perfetta delle forme d’onda classiche sopra elencate, la quale ha un alto contenuto armonico, che non varia in base alla frequenza (ie una forma d’onda a 50 Hz ha lo stesso numero di armoniche di una a 1000 Hz), e cio’ risulta essere un problema quando si lavora con strumenti musicali digitali.
Nel caso di SqrOsc si puo’ pensare ad un suono (onda quadra) con un numero infinito di armoniche. Cio’ significa che si avra’ un tot di armoniche con freqenza superiore alla frequenza di Nyquist (frequenza di campionamento / 2), al quale corrisponde il limite in banda di un sistema digitale.
Le frequenze che superano questo limite, non scompaiono dallo spettro ma vengono ribaltate.
Prendendo in considerazione un sistema con frequenza di campionamento pari a 48 kHz (48000 Hz), possono essere generate tutte le frequenze inferiori a 24 kHz (24000 Hz). Quando questa soglia viene suprata, le frequenze vengono ribaltate nel seguente modo:
y = x-SR
dove:
x >= SR/2 e rappresenta la frequenza in Hz
SR = sample rate (frequenza di campionamento)
Quindi nel caso di un sistema a 48 kHz, se si prova a generare una frequenza pari a 25000 Hz, si otterra’ come risultato una frequenza pari a -23000 Hz per la formula di cui sopra.
Il segno meno “-” suggerisce che la fase e’ stata invertita.
E’ chiaro a questo punto che questo comportamento e’ indesiderato nel caso di strumenti musicali digitali (ma non solo), in quanto il contenuto armonico e di consegueza il timbro dello strumento puo’ essere facilmente alterato. Allo stesso tempo pero’, non si vuole rinunciare all’utilizzo di forme d’onda diverse da quella sinusoidale.
Esistono varie tecniche utilizzate per aggirare questo problema. Quella presa in considerazione in questo esempio prevede l’utilizzo di lookup table, degli array contenenti forme d’onda (wavetable) utilizzati al posto dei generatori d’onda (oscillatori). L’idea e’ quella di avere piu’ lookup table contenenti la stessa forma d’onda ma con diverso numero di armonici (ie prima lookup table ha un’onda quadra con 15 armonici, la seconda lookup table una forma d’onda quadra con 8 armonici, etc.), per poi poter scegliere quella da utilizzare in base alla frequenza fondamentale della nota che si intende riprodurre. Piu’ la nota e’ alta minore sara’ il contenuto armonico della forma d’onda.
Essendo le lookup table delle tabelle (file audio), necessitano di un ulteriore UGen utilizzato per leggere I valori da esse contenuti. Generalmente si utilizza un ramp generator, che in ChucK (ed in molti altri linguaggi di programmazione audio) e’ l’UGen Phasor.
Questa tecnica risulta essere uno dei compromessi piu’ utilizzati, e come tutti I compromessi ha ovviamente pro e contro (uno dei contro e’ che non e’ facile modificare il contenuto delle lookup table in tempo reale, mentre puo’ essere relativamente facile modificare un algoritmo che genera la forma d’onda in tempo reale. Uno dei pro e’ che dal punto di vista computazionale e’ meglio avere una lookup table che singoli oscillatori quando si ha che fare con forme d’onda complesse).
In ChucK esistono degli UGen che fungono da lookup table, e sono quelli appartenenti alla famiglia dei GenX. Nell’esempio illustrato a breve, verra’ utilizzato Gen10, il quale attraverso il metodo .coeff(), genera automaticamente una forma d’onda in base all’argomento ricevuto.
Nel caso specifico, l’argomento deve essere un’array di numeri in virgola mobile, il quale rappresenta l’ampiezza delle varie sinusoidi (parziali) che compongono la forma d’onda desiderata. Le celle dell’array corrispondono alle parziali della forma d’onda (cella nr 1 = fondamentale, cella 2 = prima armonica, cella 3 = seconda armonica, etc.), per un massimo di 100 argomenti e quindi 100 parziali.
L’immagine seguente illustra il risultato, in termini di contenuto armonico, ottenuto utilizzando l’array [1., 0., 0.75, 0., 0.5, 0., 1., 0., 0., 0.5]
Si puo’ intuire dunque che Gen10 non fa altro che effettuare una sintesi additiva in base all’argomento ricevuto, e ne salva il risultato (forma d’onda) in un array.
Come accennato in precedenza il modo utilizzato per accedere ai dati contenuti in questo array, per leggere l’array, prevede l’utilizzo di una rampa collegata all’ingresso di Gen10.
L’UGen Phasor genera una rampa in un range da 0 ad 1, e puo’ essere collegato all’ingresso di un UGen Gen10 per far si che questo generi un segnale in uscita corrispondente alla forma d’onda salvata al suo interno.
I valori generati da Phasor (qualcosa di molto simile a 0, 0.001, 0.002, 0.003, 0.004, …, 0.999, 1. - per poi ripartire da 0) vengono utilizzati come indice dell’array contenuto in Gen10.
Avendo come riferimento l’immagine precedente, l’asse y di phasor corrisponde all’asse x della lookup table.
Quindi quando l’output di phasor e’ 0.5 (meta’ rampa) si stara’ leggendo il valore al centro della lookup table, quando l’output di phasor e’ 0.75, si stara’ leggendo il valore salvato nel punto x = ¾ * (lunghezza dell’array), e cosi’ via.
In questo scenario la frequenza (Hz) di Phasor influenza la velocita’ con cui la lookup table viene letta e di conseguenza la frequenza del segnale in uscita.
ANALISI DEL PROGRAMMA
Il programma come tutti quelli precedenti inizia con la dichiarazione degli UGen e delle variabili globali:
Gen10 square_1; // note da 0 a 60 Gen10 square_2; // note da 61 a 80 Gen10 square_3; // note da 81 a 105 Gen10 square_4; // note da 106 a 127 Phasor phasor; // utilizzato per controllare gli UGen Gen10 Step step => Envelope line => phasor; Envelope env => Gain master => dac; step.next(1); phasor.sync(0); float coefficients[0]; // coefficienti degli UGen Gen10 initSquareWave(); // connessioni MIDI MidiIn mIn; MidiMsg msgIn; mIn.open("Launchkey MK2 25 MIDI 1"); // variabili 144 => int NOTE_ON; 128 => int NOTE_OFF; 176 => int CTRL_CHANGE; 0 => int MIDI_CHANNEL; // canale MIDI - range da 0 a 15 float fr; float amp; int midiNote; int lastNote; 0.007874016 => float dividedBy127; 0.05 => float freqInterpolation; // in secondi [21,22,23,24,25,26,27,28] @=> int knobs[]; // control change corrispondenti agli 8 potenziometri presenti sul controller 0.1 => amp; master.gain(amp); // impostare l'ampiezza del Gain 'master' 10::ms => dur attackTime; // tempo di attacco 500::ms => dur releaseTime; // tempo di rilascio line.time(freqInterpolation); // imposta il tempo di interpolatione della frequenza dell'oscillatore
Come prima cosa vengono creati 4 Gen10 (lookup table) ed un Phasor. Quest’ultimo viene controllato in frequenza da una catena Step => Envelope. Questo, come visto negli esempi precedenti permette di avere l’effetto portamento (interpolazione del segnale che controlla la frequenza).
Viene poi chiamata la funzione initSquareWave(), che e’ dichiarata in seguito nel programma dopo ciclo while. Questa permette di inizializzare le lookup table, creando le 4 forme d’onda quadra con differenti contenuti armonici.
Il codice successivo, fino all’inizio del ciclo while non presenta niente di diverso da quello affrontato nel tutorial precedente.
A seguire si ha:
while(true) { // avanza ad ogni messaggio MIDI ricevuto mIn => now; while(mIn.recv(msgIn)) { if(msgIn.data1 == (NOTE_ON + MIDI_CHANNEL) && msgIn.data3 != 0) { // resetta il volume prima di generare una nuova nota per evitare 'glitch' env.duration(3::ms); env.keyOff(1); 3::ms => now; msgIn.data2 => midiNote; setSquareWave(midiNote); // seleziona la wavetable in base alla nota ricevuta Std.mtof(midiNote) => fr; line.target(fr); msgIn.data2 => lastNote; msgIn.data3 * dividedBy127 => float amplitude; env.gain(amplitude); env.duration(attackTime); env.keyOn(1); } else if( (msgIn.data1 == (NOTE_ON + MIDI_CHANNEL) && msgIn.data3 == 0 && msgIn.data2 == lastNote) || (msgIn.data1 == (NOTE_OFF + MIDI_CHANNEL) && msgIn.data2 == lastNote) ) { env.duration(releaseTime); env.keyOff(1); } else if(msgIn.data1 == (CTRL_CHANGE+MIDI_CHANNEL) && msgIn.data2 == knobs[0]) { setIntep(msgIn.data3) => freqInterpolation; line.time(freqInterpolation); } } }
Il main loop inizia con qualcosa di nuovo. Ogni qual volta un messaggio MIDI di tipo note on viene ricevuto il seguente codice, prima di suonare la nota ricevuta, resetta il volume dell’oscillatore (di Gen10 in questo caso) ed aspetta 3 millisecondi prima di procedere:
env.duration(3::ms); env.keyOff(1); 3::ms => now;
Questo piccolo pezzo di codice serve ad eliminare eventuali glitch, rumori indesiderati che possono essere causati dal cambio repentino di frequenza dell’oscillatore (ie si passa da una nota a 146.83 Hz ad una a 8372.01). Una situazione del genere potrebbe altrimenti creare delle discontinuita’ nel segnale, che si manifesterebbero nel dominio audio sotto forma di glitch (clicks, pops, etc.).
A seguire la nota MIDI ricevuta viene passata come argomento alla funzione setSquareWave(), anche questa dichiarata alla fine del codice nella sezione FUNZIONI. Questa funzione seleziona la lookup table da utilizzare in base alla nota MIDI. Piu’ la nota e’ alta (frequenza in Hz maggiore) meno armoniche devo essere utilizzate, e dunque una lookup table con meno armoniche viene selezionata.
Il resto del codice presente nel ciclo while e’ lo stesso utilizzato nel tutorial precedente.
A questo punto si ha la sezione dove le funzioni vengono dichiarate. La prima e’ setInterp(), spiegata nel tutorial parte 6.
A seguire le funzioni setSquareWave() e initSquareWave():
function void setSquareWave(int x) { // seleziona l'UGen Gen10 in base alla nota ricevuta. // I diversi Gen10 hanno un diverso numero di armoniche, // piu' e' alta la nota selezionata meno armoniche si avranno // per evitare problemi di aliasing if(x <= 70 && square_1.isConnectedTo(env) == 0) { phasor => square_1 => env; phasor =< square_2 =< env; phasor =< square_3 =< env; phasor =< square_4 =< env; <<< "SQUARE 1" >>>; } else if(x > 70 && x <= 90 && square_2.isConnectedTo(env) == 0) { phasor =< square_1 =< env; phasor => square_2 => env; phasor =< square_3 =< env; phasor =< square_4 =< env; <<< "SQUARE 2" >>>; } else if(x > 90 && x <= 108 && square_3.isConnectedTo(env) == 0) { phasor =< square_1 =< env; phasor =< square_2 =< env; phasor => square_3 => env; phasor =< square_4 =< env; <<< "SQUARE 3" >>>; } else if(x > 108 && x <= 127 && square_4.isConnectedTo(env) == 0) { phasor =< square_1 =< env; phasor =< square_2 =< env; phasor =< square_3 =< env; phasor => square_4 => env; <<< "SQUARE 4" >>>; } } function void initSquareWave() { // crea 4 diverse lookup table, con contenuti armonici different. // onda quadra - formula: y = sum[(1/k)*sin(2PI*f*k*t)]; con k=1,3,5,7,9,... // square_1: 14 parziali for(1=>int c; c<15; c++) { ((c * 2) - 1) => int odd; // solo numeri dispari coefficients.size(odd); // ridimensiona l'array 1. / odd => float amp; // 1/n amp => coefficients[odd-1]; } square_1.coefs(coefficients); // square_2: 7 parziali for(1=>int c; c<8; c++) { ((c * 2) - 1) => int odd; coefficients.size(odd); 1. / odd => float amp; amp => coefficients[odd-1]; } square_2.coefs(coefficients); // square_3: 3 parziali for(1=>int c; c<4; c++) { ((c * 2) - 1) => int odd; coefficients.size(odd); 1. / odd => float amp; amp => coefficients[odd-1]; } square_3.coefs(coefficients); // square_4: 1 parziale - sinusoide for(1=>int c; c<2; c++) { ((c * 2) - 1) => int odd; coefficients.size(odd); 1. / odd => float amp; amp => coefficients[odd-1]; } square_4.coefs(coefficients); }
setSquareWave(), come gia’ detto in precedenza, si occupa di scegliere la lookup table giusta in base alla nota MIDI ricevuta. Infatti quando quest’ultima viene passata come argomento, viene controllato il suo valore e che la lookup table da utilizzare (in base alla nota MIDI) non sia gia’ in uso.
Per fare cio’ viene utilizzato il metodo comune a tutti gli UGen, isConnectedTo(nomeDell’UGen):
square_1.isConnectedTo(env) == 0
Utilizzando questo metodo si puo’ capire se un UGen A e’ connesso ad un altro UGen B.
Il valore restituito da isConnectedTo() e’ 1 nel caso in cui I due UGen sono connessi, altrimenti e’ 0.
Nel caso in cui la nota MIDI e’ nel range desiderato (ie nota <= 70) ed il risultato di isConnectedTo() e’ 0, viene eseguito il codice nelle parentesi graffe {}.
I 4 if contenuti in setSquareWave, hanno tutti una struttura simile:
In termini pratici, questo codice non fa altro che connettere l’output di phasor esclusivamente alla lookup table desiderata, e di connettere solo l’output della lookup table desiderata all’inviluppo env.
Per disconnettere due UGen si utilizza l’operatore UnChucK (=<).
Il motivo per cui si effettuano tutte queste operazioni e’ semplicemente per evitare calcoli inutili. Solo un Gen10 alla volta e’ necessario per generare la forma d’onda desiderata, e lasciare phasor connesso a piu’ Gen10 sarebbe uno spreco, in quando ogni operazione ha un costo computazionale che influenza le performance del programma.
Lasciare phasor connesso a tutti i Gen10 equivale a lasciare tutte le luci accese in un appartamento, anche se si e’ da soli, chiusi in una stanza. Come risultato si avra’ un maggiore consumo di corrente.
Nelle ultime righe di codice viene dichiarata la funzione initSquareWave() che genera le 4 forme d’onda quadra, ognuna con un diverso numero di parziali.
Questa funzione non ha bisogno di argomenti e quando invocata come prima cosa crea un array di tipo float con lunghezza pari a 0, a cui successivamente aggiunge I valori corrispondenti all’ampiezza delle parziali della forma d’onda.
Questa operazione si ripete 4 volte (una volta per onda quadra, per Gen10).
Per fare cio’ viene utilizzato una nuova struttura di controllo, il ciclo for:
Questo ciclo esegue il codice presente tra le parentesi graffe {} un numero x di volte, in base alla dichiarazione presente tra le parentesi tonde ().
for necessita di una variabile con un valore noto (non nulla - il valore puo’ essere anche 0), di una condizione da valutare e di un’operazione da svolgere per far si che il codice tra le parentesi graffe {} venga eseguito.
for(variabile; condizione; operazione) { codice da eseguire un numero ‘n’ di volte } for(5 => int c; c > 0; c--) { <<< c >>>; }
Questo breve esempio puo’ essere interpretato nel seguente modo:
affinche ‘c’ (che ha valore 5) e’ maggiore di 0, decrementa ‘c’ di 1, e stampa il suo valore sulla console. Quando ‘c<=0’ interrompi il loop e prosegui nel programma.
Il risultato sara’:
5 :(int) 4 :(int) 3 :(int) 2 :(int) 1 :(int)
Quello che succede in pratica e’:
la variabile c viene creata e gli viene assegnato il valore 5
viene controllato che e’ maggiore di 0
viene eseguito il codice tra le parentesi graffe {}
a c viene assegnato il valore (c-1) – in ChucK ed altri linguaggi di programmazione il valore delle le variabili puo’ essere incrementato e/o diminuito di 1, semplicemente utilizzando nomeDellaVariabile++ oppure nomeDellaVariabile-- (http://chuck.cs.princeton.edu/doc/language/oper.html#incdec)
il codice tra le parentesi graffe {} viene ripetuto e a c viene sottratto 1, affinche’ c>0
Tornando al codice in esame, il ciclo for esegue le seguenti operazioni:
((c * 2) - 1) => int odd; // solo numeri dispari coefficients.size(odd); // ridimensiona l'array 1. / odd => float amp; // 1/n amp => coefficients[odd-1];
La variabile c dichiarata nel costrutto for viene utilizzata per inizializzare la variabile odd con solo numeri dispari:
(1*2) -1 = 1
(2*2) -1 = 3
(3*2) -1 = 5
etc.
L’array dichiarato all’esterno del ciclo for viene ridimensionato (era di lunghezza 0 al momento della sua dichiarazione) utilizzando il metodo size(). La variabile amp viene creata e gli viene assegnato un valore pari a 1/odd. Infine amp viene salvata in una cella (odd-1) dell’array coefficients.
Queste 4 righe di codice non fanno altro che calcolare l’ampiezza delle parziali di una forma d’onda quadra in accordo con la seguente formula:
y = sum[(1/k)*sin(2PI*f*k*t)]; con k=1,3,5,7,9,...
la quale dice che per ottenere una forma d’onda quadra serve sommare solo sinusoidi dispari con ampiezza uguale a 1/n con n = numero della parziale.
Utilizzando Gen10 non e’ necessario pero’ effettuare nessuna operazione se non il calcolo dell’ampiezza delle armoniche. Le operazioni trigonometriche avvengono all’interno dell’UGen stesso.
Alla fine di ognuno dei 4 cicli for si ha un rigo di codice del tipo:
square_1.coefs(coefficients);
il quale passa l’array appena generato come argomento al metodo .coefs(), che fa si che la forma d’onda desiderata venga generata e salvata in uno dei 4 UGen Gen10.
I 4 cicli for sono identici a parte per il numero delle parziali che vengono create all’interno delle parentesi graffe {}, e dunque alla durata del loop for.
Questo e’ dovuto alla differenza nel codice contenuto nelle parentesi tonde () che seguono for:
for(1=>int c; c<15; c++)
for(1=>int c; c<8; c++)
for(1=>int c; c<4; c++)
for(1=>int c; c<2; c++)
Il primo ciclo for genera 14 parziali, il secondo 7, il terzo 3 e l’ultimo 1.
RIEPILOGO
utilizzo di lookup table - UGen Gen10
generatore d'onda quadra limitata in banda
connettere e disconnettere UGen
struttura di controllo "for"
Il codice ed il testo possono essere scaricati qui: https://bitbucket.org/mariobuoninfante/chuck_workshop/src