Tumgik
#releasetime
asteracaea · 8 months
Text
9 notes · View notes
toddcoburn · 4 months
Text
Essential drill to help with success blocking pitches in the dirt!
Essential drill to help with success blocking pitches in the dirt! https://www.youtube.com/watch?v=uETlly5mNBM A common mistake, especially with in experienced catchers is to either not get the mitt all the way to the ground or lift the mitt when the ball hits the ground. It is typically done because the catcher is attempting to catch the ball with their mitt instead of their belly button. Catchers need to get their mitt down and keep it down because the ball doesn't always bounce up, sometimes it will skip or scoot along the ground. Use this "Rolling Block Drill" to practice getting and keeping your mitt down while blocking. ✅ For more information about my camps, please visit my website: https://ift.tt/yWGK5hI ✅ Also check our virtual training programs: https://ift.tt/80IuCdg Use this simple drill to get you or your catcher to take a shorter step and help decrease the release time and in turn, decrease the catchers pop time. Video Title: Great drill to practice getting the mitt down and keep it down! 🔔Subscribe now to learn the art of catching up through camps, virtual training, and exclusive social media content: https://t.ly/lv-re ✅ Stay Connected With Me. 👉Facebook: / thecatchingguy 👉Instagram: / the_catchin. . 👉Twitter(X) : / thecatchingguy 👉TikTok: / thecatchingguy 👉Shopify Store: https://ift.tt/akI69Wj 👉The Catchers Toolkit: https://bit.ly/45foMRP 👉The Catching Guy FREE Facebook Group: https://bit.ly/44QrBsG 👉The Catching Guy VIP Facebook Group (For people in a subscription group or who bought a program): https://bit.ly/3DMmFt3 ✅ For Business Inquiries: [email protected] ============================= ✅ Recommended Playlists 👉 Throwing Fundamentals: • Stop The Struggle: Perfect Your Catch... 👉 Game Savvy Tips: • Tips For Pitch Calling & Pitch Sequen... 👉 Characteristics of a Successful Catcher: • Catch, Block, Lead: Essential Qualiti... ✅ Other Videos You Might Be Interested In Watching: 👉 Ball drop and catch for grip and shoulder strength • Boost Your Catching Skills: Ball Drop... 👉 Learn how to block pitches in the dirt better with this Catchers Blocking Drill Progression. • Master Pitch Blocking: A Comprehensiv... 👉 Decrease your release & pop time w/ this simple drill! • Improve Your Game: Simple Drill to De... 👉 HS team loses championship on dropped third strike mistake by the catcher. • Baseball Championship Lost: A Lesson ... 👉 Throwing from a knee-down setup, what do you prefer? • Top Catcher's Technique: Throwing fro... ============================= ✅ About Todd Coburn - The Catching Guy. My name is Todd Coburn. I help catchers, coaches & parents of catchers learn about the position through my camps, virtual training programs & social media. Over the last several years, I have become one of the most sought-after catching coaches in the world. I'm known not only for my passion for catching but also for teaching the position. I'm a lifetime catcher who loves spreading knowledge to anyone who wants to listen & learn. Who am I? 👉🏻 2-time draft pick Houston Astros 👉🏻 Former pro catcher, Phillies Org. 👉🏻 Former collegiate catching coach at Cuesta JC, Cal Poly & College of Southern Idaho 👉🏻 Former Program Development Coordinator for Velocity Sports Performance 👉🏻 Nearly 200,000 followers on social media 👉🏻 Over 30 years of experience coaching catchers 👉🏻 Master of Science in Kinesiology (Teaching & Coaching Focus) ==================== #catcherthrowing #poptime #baseballtraining #throwingstep #releasetime #catcherdrills © Todd Coburn - The Catching Guy via Todd Coburn - The Catching Guy https://www.youtube.com/channel/UCaDzCs-NgHHZspbEwLy7JAA February 05, 2024 at 08:05AM
0 notes
don-lichterman · 2 years
Text
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
View On WordPress
0 notes
Text
Schau dir "Akon - Lonely - ( Extended Mix )( Dj Dani Bootleg ) 2021" auf YouTube an
youtube
1 note · View note
aproducerslife · 6 years
Video
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
1 note · View note
23percentchallenge · 4 years
Photo
Tumblr media
Motivation for the Week Featuring Love 💕 Day #23percentchallenge #loveday #selfhelp #stoptime #kiss #travelintime #read #escapetime #music #feeltime #write #releasetime #breathe https://www.instagram.com/p/CAdHhcxp1Y8/?igshid=1qm9qkgfcalt2
0 notes
arvindingcheng · 6 years
Link
Do you know when does all Apple iPhone launch time? Here I have collected the Apple iPhone released time from iPhone 1 to the newest iPhone XS 2018.
0 notes
Photo
Tumblr media
#lifeisstrange #captainspirit #theawsomeadventuresofcaptainspirit #gamerelease #gaming #releasetime #worldrelease #videogame #freegame #free #cantwait #life #strange #lifeisstrangegame
0 notes
monica82movies · 7 years
Photo
Tumblr media
#selfhelp #how #stoptime #kiss #travelintime #read #escapetime #music #feeltime #write #releasetime #breathe
0 notes
trainwiz · 2 years
Note
Is the space required on the steam page for Underspace up to date? I'm not made of hard drives.
The Steam page's gonna be updated closer to releasetimes. The space required is gonna be more around 7-10gb.
It's a big game Stanley. A big game indeed.
1 note · View note
matt1021990 · 2 years
Photo
Tumblr media
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
1 note · View note
375auralassaults · 4 years
Audio
/*ASSAULT #44 : please adjust your radio dial
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. */
( { var gate = LFNoise1.kr(25, 0.1, 0).poll; var noiz = PinkNoise.ar() * Env.asr(0.01, 1,releaseTime:0.01).kr(gate: gate); var filt = Splay.arFill(14, { [RLPF.ar(noiz, Demand.kr(gate, 0, Drand(Array.fill(12, {rrand(50, 1500)}),inf)),rrand(0.01,0.5)), RHPF.ar(noiz, Demand.kr(gate, 0, Drand(Array.fill(12, {rrand(3500, 5500)}),inf)),rrand(0.0075,0.075))].choose; }, level: 1/14, levelComp: false); Normalizer.ar( filt ); }.play )
0 notes
aproducerslife · 6 years
Video
Spät Nachts der #parentaladvisory Teaser zur se trouver EP! FSK 18! #EP #sneakpreview #inthestudio #kopfkinomusik #apl #aproducerslife #elektronischemusik #einProduzentenleben #einbisschenschweben #TEASER #kreativfabrik #bassistliebe #gedankenimquadrat #electronica #house #electronica #elektronischetanzmusik #einProduzentenleben #träumelebenleben #releasetime #fsk18
1 note · View note
reixperiment · 4 years
Text
Tumblr media Tumblr media Tumblr media
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
int time = millis();
//SinOsc sine;
Capture video;
// Times and levels for the ASR envelope
float attackTime = 0.001;
float sustainTime = 0.004;
float sustainLevel = 0.3;
float releaseTime = 0.2;
// This is an octave in MIDI notes.
int[] midiSequence = { 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 };
// Play a new note every 200ms
int duration = 200;
// This variable stores the point in time when the next note should be triggered
int trigger = millis();
// An index to count up the notes
int note = 0;
void setup() {
size(600, 400);
// Make a new instance of a PImage by loading an image file
video = new Capture(this,640,480,30);
video.start();
arduino = new Arduino(this, Arduino.list()[0], 57600);
saw = new SawOsc(this);
//saw.play();
// Create the envelope
env = new Env(this);
}
void captureEvent(Capture video){
}
void draw() {
float (arduino.analogRead(0));
float m = map(arduino.analogRead(0), 0, 500, 0, 1000);
//fill(255);
//ellipse(500, 500, m, m);
//background(0);
println(arduino.analogRead(0));
float amplitude = map(mouseY, 0, height, 1.0, 0.0);
saw.amp(amplitude);
// Map mouseX from 20Hz to 1000Hz for frequency
float frequency = map(arduino.analogRead(0), 0, 500, 20.0, 1000.0);
saw.freq(frequency);
// Map mouseX from -1.0 to 1.0 for panning the audio to the left or right
float panning = map(mouseX, 0, width, -1.0, 1.0);
saw.pan(panning);
image(video,0,0,640,480);
video.read();
int passedMillis = millis() - time; // calculates passed milliseconds
if(passedMillis >= m){
time = millis();
tint(0,0,m); // if more than 215 milliseconds passed set fill color to red
} else {
tint(255,0,0,100);
fill(time % 255);
}
// If the determined trigger moment in time matches up with the computer clock and
// the sequence of notes hasn't been finished yet, the next note gets played.
if ((millis() > trigger) && (note<midiSequence.length)) {
// midiToFreq transforms the MIDI value into a frequency in Hz which we use to
// control the triangle oscillator with an amplitute of 0.5
saw.play(midiToFreq(midiSequence[note]), 0.5);
// The envelope gets triggered with the oscillator as input and the times and
// levels we defined earlier
env.play(saw, attackTime, sustainTime, sustainLevel, releaseTime);
// Create the new trigger according to predefined duration
trigger = millis() +arduino.analogRead(0);
// Advance by one note in the midiSequence;
note++;
// Loop the sequence, notice the jitter
if (note == 12) {
note = 0;
}
}
}
// This helper function calculates the respective frequency of a MIDI note
float midiToFreq(int note) {
return (pow(2, ((note-69)/12.0))) * 440;
}
0 notes
pcgamesplay1 · 4 years
Text
Fallout 76 | Wastelanders 14th April, 2020 | Release Times
Fallout 76 | Wastelanders 14th April, 2020 | Release Times #bethesda #FALLOUT76 #NPC #PCG1 #ReleaseTimes #Survival
View On WordPress
0 notes
mbuoninfante · 6 years
Text
MonoSynth in ChucK - pt.7
Parte 7
SCOPO
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]
Tumblr media
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.
Tumblr media
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:
phasor => square_1 => env;   phasor =< square_2 =< env;     phasor =< square_3 =< env;     phasor =< square_4 =< env;
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:
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];   }
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
0 notes