Equip multi-efectes per a guitarra elèctrica basat en el...
Transcript of Equip multi-efectes per a guitarra elèctrica basat en el...
Disseny i realització d’un equip multi-efectes per a
guitarra elèctrica basat en el DSP TMS320C5535
TITULACIÓ: Grau d’Enginyeria Electrònica Industrial I Automàtica
AUTOR: Lluc Sementé
DIRECTORS: Jesús Jorge Brezmes
DATA: Setembre/ 2016.
Índex
1.Introducció 5
1.1 Punt de partida i disseny general 6
2.Unitat de control, el DSP TMS320C5535 7
2.1 TMS320C5535 eZdsp USB Kit 7
2.1.1 DSP C5535 10
2.1.2 Bus I2S 10
2.1.3 BUS I2C 11
2.1.4 Connector expansió 12
3. Interfície física 14
3.1 Secció del interruptor de palanca 14
3.2 Secció del interruptor rotatori 15
3.3 Secció dels potenciòmetres 16
3.4 Connectors Jack 17
3.5 Resultat final 18
4. Efectes de So 19
4.1 Clean 20
4.2 Distorsió 21
4.3 Delay 23
4.4 Chorus 24
4.5 Flanger 27
4.6 Phaser 29
4.7 Auto Wah-Wah 32
4.8 Equalitzador 35
5. Codi funcional 38
6. Conclusions 44
7. Bibliografia 45
I n t r o d u c c i ó
5
1.Introducció
Aquest projecte tracta de l’elaboració d’un equip multi-efectes per a guitarra elèctrica. Es
tracta d’emular els efectes comercialitzats pels grans fabricants més típics i fàcilment
audibles què s’utilitzen en el món de la música. Els efectes implementats en aquest treball
es divideixen en dos grups. Els basats en línies de retards temporals ( Delay, Chorus i
Flanger) i els que modifiquen l’espectre de freqüència de la senyal original ( Equalitzador,
Phaser i Auto Wah-Wah) sent aquests últims, més complexos i exigents de reproduir.
Per tal de desenvolupar aquest projecte s’ha utilitzat un processador digital de senyals (DSP)
de Texas Instuments, muntat sobre la placa de avaluació del mateix fabricant, eZdsp C5535.
Aquest dispositiu és l’encarregat de mostrejar la senyal de la guitarra a 48kHz i 16 bits
mitjançant ADC, aplicar els efectes a través del codi programat en C seguint les pautes i
esquemes presents en la literatura universitària (ja que les empreses són molt restrictives
amb els seus algoritmes) i, finalment reconstruir el senyal modificat a traves d’un DAC.
Tot i que les estructures bàsiques dels efectes estan presents de forma clara en la literatura,
una vegada estudiades i programades, no tenen el mateix so que un dispositiu analògic o un
dispositiu digital de les equips professionals, degut a la falta d’experiència bàsicament . Com
sempre es diu, el format analògic té un caliu propi difícil d’emular.
Per comandar tots aquests elements, s’ha dissenyat i elaborat una placa de gestió d’entrades
basada en un conjunt de vuit potenciòmetres , un interruptor rotatori i un interruptor de
palanca. Tot això comandat amb l’ajuda d’un multiplexor què intercanvia els diferents
potenciòmetres què llegeixen els ports analògics. Mitjançant aquests, podrem regular
diferents paràmetres per cada efecte, el volum general de cada canal, selecció de canal i
selecció d’efecte.
La peculiaritat d’aquest projecte és que permet la fàcil reprogramació del sistema, per tant,
un ventall infinit de possibilitats de creació i edició de nous efectes en funció de les
necessitats del músic. És possible, també, endolla’l a el corrent directament i que funcioni,
ja que la placa DSP té la capacitat d’arrancar codi des d’una targeta SD, qualitat què permet
ser utilitzat en directe damunt d’un escenari.
Finalment, aclarir que tots el components seleccionats durant el disseny del projecte han
estat, en primer lloc, elegits pel seu preu i per tant, l’equip no inclou un speaker propi. S’ha
d’acoblar el sistema a un amplificador normal de guitarra o connecta’l a uns casc.
I n t r o d u c c i ó
6
1.1 Punt de partida i disseny general
Per tal de dur a terme un equip multi-efectes per guitarra elèctrica, es necessita algun tipus
de dispositiu microcontrolador què permeti la captura del senyal de la guitarra en temps real
(o gairebé real), aplicar diferents algoritmes que simulin etapes analògiques d’efectes i/o
saturació i finalment, treure el senyal per un altre port.
Totes aquestes tasques tenen que ser recolzades, a la vegada, per una interfície física què
permeti interactuar amb la màquina i modular aquests efectes segons la voluntat de l’usuari.
Per tant, el projecte inclourà un conjunt de potenciòmetres i selectors, ja siguin interruptors
de palanca, botons o interruptors rotatoris connectats al dispositiu microcontrolador.
Usualment, aquest tipus d’aparells tenen la capacitat de simular diferents canals, és a dir,
diferents modificacions del timbre de la guitarra. Podem distingir a gran escala entre dos
sons bàsics. El so natural de la guitarra, normalment anomenat canal net (Clean channel) i
la distorsió ( Distortion/Overdrive Channel). Tot i que les distorsions consten d’un ampli
ventall de subclasses i categories , jo em limitaré a imitar el típic so de guitarra saturada dels
amplificadors més estàndards.
Aspiro també, a que el producte final del projecte sigui reprogramable, ja que com a músic
i aficionat dels efectes electrònics, m’agradaria poder experimentar més endavant amb la
guitarra i provar coses noves o si més no, imitar efectes i poder reproduir-los damunt d’un
escenari.
Finalment, aclarir que tot i ser un aficionat a aquest tipus de dispositius, en desconec total o
parcialment el seu funcionament i per tant em veure subjecte als propis avanços que jo pugui
fer consultant la literatura pertinent i l’estudi concret de la matèria.
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
7
2.Unitat de control, el DSP TMS320C5535
Com s’ha comentat anteriorment, requereixo d’un dispositiu microcontrolador per tal de
gestionar i sintetitzar totes les funcionalitats del projecte, es tracta, doncs, de l’ànima del
projecte i la decisió més important de totes. Una mala elecció pot suposar la fallida del
projecte o la ineficiència d’aquest.
Hi havia varies opcions a primer cop d’ull que podien semblar aptes per realitzar un projectes
d’aquest tipus. Es pot pensar en els famosos Arduinos, alguns microcontroladors típics de
grans fabricants ( Texas Instruments, Microchip...), FPGAs, DSPs.
Per tal de elegir el més adequat, tant pel projecte com per a mi mateix, ja que m’hauré
d’enfrontar a una màquina amb la qual probablement mai hauré treballat i això també és un
factor a considerar, vaig haver de fer una comparativa entre diferents tipus de dispositius.
Primerament, es requereix una alta velocitat de computació per tal de realitzar els efectes.
En aquesta categoria l’Arduino es queda sobre els 20 MHz, què pot semblar una alta velocitat
de còmput, però si es té en compte que haurem de mostrejar l’àudio entre 48000 Hz i 44100
Hz i que s’hauran d’aplicar tots els efectes, potser que ens quedem curts. D’altra banda tant
els microcontroladors comuns , els FPGAs i els DSPs tenen la possibilitat de utilitzar cristalls
externs en cas de falta de recursos. Per tant, vaig decidir no arrisca en aquest aspecte i vaig
descartar els Arduinos.
Descartada una opció, quedaven encara tres grans famílies, i tot i ser bastant òptimes les tres,
després de consultar diversos documents relacionats amb l’enginyeria del so, s’apuntava a
que l’industria es focalitza en els FPGA i els DSP, tant per la seva flexibilitat com per la
literatura què suporta els projectes d’aquest tipus en aquests dispositius. La filosofia de
programació és bastant diferent en ambdós dispositius. En un manipules hardware i en l’altre
software. Tot i estar més o menys instruït en ambdues disciplines, em trobava més còmode
en la programació en C i vaig decidir deixa la decisió final al factor més important,
l’econòmic.
Em vaig ficar a navegar per el catàleg de RS online, i tot i que en un primer moment em vaig
sentir una mica abromat per tal quantitat d’opcions, ràpidament vaig trobar el que seria el
cervell del projecte. Una placa de prototips de Texas Instruments basada en el DSP C5535.
El preu, uns 120 €.
2.1 TMS320C5535 eZdsp USB Kit
La placa de prototips en qüestió, s’adapta increïblement bé a les necessitat del meu projecte
i m’ha permès desenvolupar-lo amb prou satisfacció. A continuació mostraré les
característiques què el fabricant anomena i en comentaré aquelles què he considerat útils pel
meu projecte:
• DSP de Texas Instruments C5535.
• Còdecs Estèreo (de entrada i de sortida) de Texas Instruments TLV320AIC3204.
• 4 busos I2S per a transporta dades de so.
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
8
• Connector de targetes Micro SD (la placa inclou una targeta Micro SD de 2GB).
• Interfície USB 2.0.
• 8 megabytes de memòria Flash per comunicació SPI.
• Pantalla OLED de 96 x 16 píxels controlada pel bus I2C.
• 5 LEDs controlables per l’usuari.
• 2 polsadors.
• Emulador incrustat USB XDS100 JTAG.
• Interfície sense fil .
• Connector d’expansió lateral de 60 pins (port P2).
• Punts de control per mesures de tensió.
• Alimentació per interfície USB.
• Compatible amb Code Composer Studio v4 i v5 de Texas Instruments.
Figura 2.1 : Placa eZdsp C5535
Primerament, inclou el dispositiu DSP C5535. Un DSP de coma fixa, low-power de la
família dels DSP C5000 de Texas Instruments.
La placa a més, inclou un còdec d’àudio, el TLV320AIC3100. Aquest és l’encarregat de
mostrejar l’entrada amb el ADC i de generar la senyal de sortida amb el DAC. Està connectat
al DSP per diferents busos dels quals disposa la placa i té compatibilitat amb diversos tipus
d’operacions. Per tal de configura’l, s’utilitza el bus I2C. Un dels estàndards de bus més
utilitzat arreu amb la finalitat de interconnectar dispositius microcontroladors amb els seus
perifèrics en una placa.
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
9
Per tal de transmetre els senyals d’àudio del còdec al DSP i viceversa, s’utilitza el bus I2S,
un bus industrial optimitzat en transmissió d’àudio entre diferents perifèrics d’un sistema
microcontrolador.
Finalment, el còdec d’àudio ja va connectat als ports Jack & Plug de la placa, fet que em
facilita la implementació de l’etapa física.
La placa també consta d’un connector d’expansió amb diversos pins GPIO i GPAIN, els
quals utilitzo per llegir i gestiona la interfície física.
Els GPIO ( General Purpose Input/Output) són pins digitals d’us general, què en funció de
les necessitats del prototip poden prendre varies funcions. En el meu cas, els he utilitzat per
accionar i commutar un multiplexor lligat als potenciòmetres de control.
Els GPAIN ( General Purpose Analog Input) són uns pins què permeten captar senyals
analògiques fins uns certs llindars. La placa disposa de 4 ports d’aquest tipus i no tots tenen
les mateixes restriccions, més endavant ho comentaré amb més detall.
La placa disposa de dos ports USB, un dels quals com a port USB 2.0 i l’altre pel JTAG i la
comunicació UART. També disposa de ‘slot’ per targeta SD i la capacitat d’arrancar
aplicacions des de aquesta seguint uns senzills passos explicats pel fabricant.
A continuació es mostra un esquema per perifèrics de la placa.
Figura 2.2 : Esquema dels components i busos de la placa eZdsp
Per acabar de complementar totes les funcionalitats i possibilitats de la placa. El producte
inclou l’IDE de Texas Instruments per desenvolupar codi, el Code Composser Studio v4,
basat en l’IDE de java Eclipse, que tot i estar una mica desfasat en el temps ( ja van pel 6.1),
permet elaborar projectes de qualsevol tipus amb molta facilitat i autonomia.
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
10
2.1.1 DSP C5535
Aquest DSP de coma fixa (fixed‑point) està basat en la generació de processadors
TMS320C55x. La arquitectura del DSP C55x aconsegueix un rendiment molt alt amb un
baix consum gràcies a la utilització de paral·lelismes, acceleració per hardware per la
realització de FFT (Fast Fourier Transform) i altres tecnologies.
La CPU suporta una estructura interna de busos què es composa d’un bus de programa, un
bus de 32 bits i dos busos de 16 bits de dades en mode lectura, dos busos de 16 bits de dades
en mode escriptura, i busos addicionals dedicats a perifèrics i activitat DMA.
Aquests busos proporcionen la possibilitat d’executar fins un màxim de quatre lectures i dos
escriptures de dades de 16 bits en un sols cicle de rellotge.
Pel que fa a la memòria, el C5535 inclou 128KB de memòria ROM i 320KB de memòria
RAM. El dispositiu també inclou quatre controladors DMA, cada un d’ells amb 4 canals,
proporcionant moviments de dades de 16 canals independents sense la intervenció de la
CPU.
El C5535 té un rellotge amb possibilitat de configuració, amb una freqüència màxima de
100MHz.
A més, posseeix dos unitats de multiplicació-acumulació (MAC), cada una d’ells capaç de
realitzar una multiplicació de 17 bits x 17 bits i una suma de 32 bits en un sols cicle de
rellotge.
2.1.2 Bus I2S
El Bus I2S és el medi pel qual viatgen les mostres d’àudio, tant les que s’han de processar
com les que ja han estat processades. Conegut també amb el nom de Inter-IC Sound o
Integrated Interchip Sound fou introduït per Philips, actualment sota el nom de NXP
Semiconductors, l’any 1986 i revisat per última vegada l’any 1996. Es tracta d’un bus sèrie
què consta com a mínim de tres línies.
Rellotge de bit (Bit Clock)
Rellotge de paraula (Word Clock)
Línia de dades multiplexada (Aplicacions estèreo)
Figura 2.3 : Comunicació I2S
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
11
El rellotge de bit és el què indica quant s’ha transmès un bit, d’altra banda el rellotge de
paraula és un indicador de canvi de canal, ja que en el format d’àudio estèreo hi ha dos canals
i per tant dos mostres diferents por cada moment significatiu.
El protocol estableix que per formats d’àudio estèreo, la mostra del canal esquerra es
transmetrà durant el nivell baix del Word Clock i la dreta durant el nivell alt. Per tan podem
concloure que el rellotge de paraula tindrà la mateixa freqüència que el mostreig.
2.1.3 BUS I2C
El bus I2C és el medi a traves del qual podem enviar dades i configurar els diferents
perifèrics de la placa des del DSP. Es tracta d’un bus multi-master/multi-slave àmpliament
utilitzat en l’industria per a connectar microcontroladors amb els seus perifèrics o per a
connectar circuits integrats entre si. Consta de tres línies de transmissió:
Figura 2.4 : Esquemàtic I2C
SDA: dades
SCL: rellotge
GND: massa
Les dues línies implicades en la comunicació són de open-drain, per tant, sempre hi haurà
tensió si ningú esta enviant cap tramesa.
La velocitat és de 100Kbit per segon en el mode estàndard, encara que també permet
velocitats de 3.4 Mbit/s.
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
12
2.1.4 Connector expansió
Com he comentat, la placa disposa d’un connector d’expansió amb diversos senyals sobre
els quals treballar, a continuació es mostra els pins i les senyals què involucren.
Figura 2.5 : Pinout del connector d’expansió
U n i t a t d e c o n t r o l , e l D S P T M S 3 2 0 C 5 5 3 5
13
Figura 2.6 : Senyals corresponents als pins
Per tal de realitzar el projecte he utilitzat el port GPAIN3, GPAIN2 i GPAIN1 per tal de
llegir els valors analògics d’uns potenciòmetres i d’un divisor de tensió muntat sobre un
interruptor rotatori.
Els ports GPIO 12, 17 i 15, emprats com a sortides, per comandar un multiplexor què té
com a sortida els ports GPAIN i com a entrades els potenciòmetres.
Finalment, el port GPIO 14, utilitzat com a entrada, s’ha assignat a una de les potes d’un
interruptor de palanca. També s’ha utilitzat els pins de GND i alimentació a 3.3V i a 5V.
I n t e r f í c i e f í s i c a
14
3. Interfície física
Per tal de poder interactuar amb el DSP, s’ha dissenyat una placa què consta de 8
potenciòmetres funcionals i 3 de inoperatius degut a un mal dimensionament inicial. Aquests
estan connectats a el multiplexor DG409 de Vishay Siliconix. Es tracta d’un multiplexor
dual de quatre canals alimentat tant en tensió dual (de +5V a +20V) com simple (de +5V a
+36V).
Figura 3.1 : chip DG409 Figura 3.2 : Esquemàtic DG409
S’han connectat els vuit potenciòmetres a les vuit entrades de les que disposa el xip i les dos
sortides connectades cadascuna als ports GPAIN2 i GPAIN3 de la placa eZdsp.
Per tal de realitzar la maniobra, mitjançant codi es manipulen els pins GPIO12, GPIO17 i
GPIO15 connectats als pins 1,16 i 2 del xip. Degut a les necessitats del xip, s’han tret dues
línies de tensió de la placa, una de 5V per alimentar el xip i una altra de 3.3V per fer la
lectura dels potenciòmetres, ja que els ports analògics GPAIN 2 i 3 , tenen un valor màxim
de lectura de 1.2 V. A continuació es mostra uns esquemàtics del circuit dissenyat i
comentaris sobre el disseny.
3.1 Secció del interruptor de palanca
S’ha optat per el disseny amb massa flotant ja que els port GPIO al ser configurats com a
entrades, per alguna raó què desconec, es situen a nivell alt de tensió. Com si es tractes d’un
port open-drain doncs, connectant ha massa s’ha corregit parcialment el problema. Tot i que
he detectat que si el PC al qual tens connectat l’equip està connectat a l’alimentador de
corrent, les masses ballen i poden aparèixer lectures errònies del port GPIO 14. S’han
introduït un parell de LED’s per tal de fer més visual i elegant el producte final.
I n t e r f í c i e f í s i c a
15
Figura 3.3 : Interruptor de palanca Figura 3.4 : Circuit del interruptor de palanca
3.2 Secció del interruptor rotatori
El interruptor rotatori és de 5 posicions més la neutra. S’ha optat per obtenir diferents valors
de tensió analògica a mode de selector d’efecte. El divisor de tensió consta de 6 resistències
de 1k ohm. De tal manera que la tensió de 5 V (4.64 reals )queda repartida de la següent
manera per cada posició:
Posició N: 0 𝑉
Posició 1: 4.64 𝑉 ∗ 𝑅
6𝑅= 0.77 𝑉
Posició 2: 4.64 𝑉 ∗ 𝑅
5𝑅= 0.92 𝑉
Posició 3: 4.64 𝑉 ∗ 𝑅
4𝑅= 1.16 𝑉
Posició 4: 4.64 𝑉 ∗ 𝑅
3𝑅= 1.54 𝑉
Posició 5: 4.64 𝑉 ∗ 𝑅
2𝑅= 2.32 𝑉
Utilitzant el mòdul SAR, s’obtenen les diferents lectures i el codi n’obté el nou estat.
Figura 3.5 : Interruptor rotatori Figura 3.6 : Circuit del interruptor rotatori
I n t e r f í c i e f í s i c a
16
3.3 Secció dels potenciòmetres
S’ha trobat convenient agafa potenciòmetres de 10K ohms, lineals, alimentats a traves d’un
divisor de tensió realitzat amb resistències de 100 ohms per evitar al màxim l’efecte de carga
amb els altres elements resistius. Tot i que es produeixen variacions de tensió quant els
potenciòmetres es troben en la posició mínima, el seu funcionament i lectura és mostren
correctes i eficaços. Els valors de tensió que donen són d’entre 0V a 1.55V (3.1/2 V). Com
he comentat anteriorment, els ports GPAIN2 i GPAIN3 accepten com a màxim 1.3 V. Per
tant es perd la resolució des de els 1.3 i a 1.55 V. Però no afecta al bon funcionament de
l’equip.
Figura 3.7 : Potenciòmetre Figura 3.8 : Circuit dels potenciòmetres i DG409
I n t e r f í c i e f í s i c a
17
3.4 Connectors Jack
Per tal de connectar la guitarra i l’amplificador, es requereix d’un connector Jack 6,35
mm, per tant, s’ha adquirit un connector femella de 6,35 mm i un mascle de 3,55 mm, ja
que el connector de la placa és de 3,55 mm.
Figura 3.9 : Femella Jack 6,36mm Figura 3.10 : Mascle Jack 3,55mm
3.5 Resultat final
Finalment, s’ha muntat tot plegat dins d’una caixa de connexions de 17 cm x 12 cm, ja que
és un format fàcilment modificable i barat. A continuació aprofito per mostra fotos del
resultat final de la interfície.
Figura 3.11 : Vista frontal
I n t e r f í c i e f í s i c a
18
Figura 3.12 : Vista interior potenciòmetres
Figura 3.12 : Vista interior circuit
E f e c t e s d e s o
19
4. Efectes de So
En el mercat hi ha molts dispositius multi-efectes en un rang de preus molt divers, des de
més de 1000 euros, fins a 50 o 100 euros. Normalment, inclouen diferents elements rotatoris
i pedals per tal de regular els efectes i alguna pantalla per visualitzar la configuració actual.
Ha continuació es mostren alguns exemples.
Figura 4.1 : Equips multi-efecte per a guitarra
Hi ha molts efectes aptes per a ser reproduïts en un projecte com el meu, però he decidit fer
una selecció d’aquells què he cregut més representatius de la música rock . Entre ells, els
elegits són:
Distorsió
Clean
Delay
Flanger
Phaser
Chorus
Auto wah-wah
Tots ells han sigut implementats amb codi C recorrent la literatura pertinent i comprenent el
seu funcionament. Com s’explicarà a continuació amb més detall, la majoria d’efectes
consisteixen en emmagatzemar mostres i multiplicar-les per diferents valors numèrics en
funció de l’estructura.
E f e c t e s d e s o
20
4.1 Clean
Per tal de reproduir el so net o natural de la guitarra, es pot senzillament, mostrejar la senyal
i reproduir-la novament en la sortida. Però per tal d’obtenir un so net una mica més complert.
He optat per buscar algoritmes de simulació de les clàssiques i mítiques vàlvules
termoiònica. El comportament d’amplificació de les vàlvules no és lineal i per tant
s’aproximarà mitjançant una corba polinòmica. Seguint l’exemple de la gent de Texas
Instuments, s’ha elaborat el canal net seguint la següent equació.
𝑦(𝑛) = 2 · 𝑥(𝑛) + 𝑥(𝑛)3 (1)
Com es veu en l’equació, la utilització de l’exponent implica generació de nous harmònics
en funció del senyal d’entrada, propietat pròpia de les vàlvules termoiòniques. La simulació
real de les vàlvules és una qüestió en la qual molta gent esta involucrada i és un dels
conceptes més buscat per les empreses, ja que el so de la vàlvula ha rebut una mitificació
molt profunda al llarg de la seva història en el mont de la música.
No és una qüestió senzilla i requereix de molta investigació i estudi del model de la vàlvula,
per això he optat per una generació d’harmònics més senzilla. A continuació es mostra el
codi.
#define A 32767
#define B 16383
Int16 Clean (Int16 sample)
{
signed long output;
if ( 0 == sample )
{
output = 0;
}
else
{
output = ( ((long)sample * (long)sample) >> 15); /* x ^ 2 */
output = (output * (long)sample) >> 15; /* x ^ 3 */
output *= B; /* Multiply by 2 before dividing by 16384 */
output += ( A * (long) sample); /* a * x ^ 1 */
output >>= ( 15 - 1 ); /* Divide by 16384 */
}
/* Limit output if overrange */
if ( output > 32767)
{
output = 32767;
}
else if ( output < -32767)
{
output = -32767;
E f e c t e s d e s o
21
}
return( (Int16) output);
}
Codi 1 : Clean
4.2 Distorsió
La distorsió o saturació, consisteix bàsicament en una deformació del senyal original causada
per la saturació de les vàlvules o transistors. El senyal es va deformant fins a arribar a semblar
un senyal quadrat degut a la característica no lineal pròpia dels components saturats. Aquest
fet genera molts harmònics d’ordre superior què són els responsables del so tan peculiar i
característic d’una guitarra distorsionada.
Es poden distingir dos procediments generals per tal de simular els efectes de la distorsió.
Els de retallament simètric suau, què consisteix en tractar el senyal de forma lineal fins un
llindar concret. Aquell senyal què sobrepassi el llindar, es veurà limitat a aquest i els valors
pròxims tractats de forma no lineal fins arribar al llindar.
D’altra banda, existeix també el retallament asimètric, propi de les distorsions més brutes i
no lineals, anomenades fuzz o buzz. Consisteix en tractar el senyal amb un comportament
totalment diferent en ambdues parts del senyal, valors negatius i positius de tensió.
E f e c t e s d e s o
22
Per tal de simular l’efecte de la distorsió, s’ha agafat una característica simètrica
completament no lineal basada en l’exponent. A continuació es mostra la característica
estàtica.
Per tal d’obtenir aquesta funció de transferència, l’equació següent ha sigut emprada:
𝑓(𝑥) =𝑥
|𝑥|(1 − 𝑒−(𝑔𝑎𝑖𝑛 ∙ |𝑥|)) (2)
A continuació es mostra el codi emprat per realitzar tal efecte:
#define A 32767
#define B 16383
#define SAT_VAL 800
Int16 Overdrive ( Int16 sample )
{
Int16 output;
long pre;
float temp;
Int16 sign;
if (sample < 0)
{
sign = -1;
temp = (float)sample * sign;
}
else
{
sign = 1;
temp = (float)sample;
}
temp = temp/SAT_VAL; // Changing to fraction (0 to 1)
if (temp > 1) temp = 1;
temp = exp(-temp*2.71828182); //Gain set to e
temp = 1 - temp;
temp = B*temp*sign;
output = (Int16)temp;
output >>= 1;
return output;
}
Codi 2 : Dirt
E f e c t e s d e s o
23
Tot i funcionar adequadament, si mesclo la distorsió amb els altres efectes no obtinc una
resposta agradable. No he aconseguit esbrinar la causa, ja que analitzant el comportament
pas a pas sembla ser que les mostres i els valors son correctes, però la placa no respon. Així
doncs, el canal de distorsió del pedal no està completat adequadament.
4.3 Delay
El Delay, com ve indica el seu nom en angles es basa en retards del senyal mesclats
juntament amb el senyal original. Aquest efecte es produeix naturalment en qualsevol espai.
Les ones sonores reboten per les parets, si les parets son molt llunyanes sentirem un eco, en
canvi si estan a prop simplement notarem la reverberació de l’espai. Per tal de realitzar aquest
efecte s’utilitza el anomenat IIR Comb Filter(Infinite Impulse Response), una estructura què
produeix infinites respostes a una sola entrada. D’aquesta manera es pot percebre una
constant repetició de la ona i com es va atenuant progressivament.
Figura 4.2 : Diagrama funcional i de Bode del IIR Comb Filter
Com es pot observar, |g| < 1 és una condició d’estabilitat del filtre, ja que en cas contrari la
realimentació amplificaria infinitament el senyal circulant. Per tal d’implementar aquest
efecte i d’altres que utilitzant una estructura semblant, s’ha utilitzat un buffer circular amb
dos apuntadors, el d’escriptura de mostres i el de lectura de mostres antigues. La distància
què separa als dos punters és el temps del Delay, per tant, per una mida de buffer fixa, el
temps màxim de Delay tindrà relació amb la meitat de la mida del buffer. En funció de les
mostres per segon aquest temps serà també més gran o petit. L’equació què defineix
l’estructura és la següent.
𝑦(𝑛) = 𝑥(𝑛) · 𝑐 + 𝑥(𝑛 − 𝑀) · 𝑔 (3)
A continuació es mostra el fragment de codi corresponent.
Int16 Delay_IIR (Int16 sample,Int16* delay_array,Int16 A, Int16 B, Int16
C )
{
Int16 output;
static int n=0;
static int k=0;
E f e c t e s d e s o
24
float CT,G,Dt;
CT = (float)A/100;
if (CT >= 1) CT = 1;
if (CT <= 0) CT = 0;
G = (float)B/100;
if (G >= 0.7) G = 0.7;
if (G <= 0) G = 0;
Dt = ((float)C/100 * 7500); //7500 is the max delay time
if (Dt >7500) Dt = 7500;
if (Dt <200) Dt = 200;
if ((k - n != (Int16)Dt ) & (n - k != (Int16)Dt))
{
k = Dt + n;
if (k>SAMPLE_ARRAY_LENGHT) k -=SAMPLE_ARRAY_LENGHT;
}
output = ( CT * sample ) + ( delay_array[n] * G) ;
delay_array[k] = output ;
if (n < SAMPLE_ARRAY_LENGHT-1) n++;
else n = 0;
if (k < SAMPLE_ARRAY_LENGHT-1) k++;
else k = 0;
return output;
}
Codi 3 : Delay
Com es pot observar en el codi, hi ha tres paràmetres variables. Els valors CT i G representen
els elements de l’estructura anteriorment mostrada vinculats a la presència de cada línia de
so en la sortida. Com més gran sigui G, més feedback hi haurà i per tant la resposta durarà
més temps, això farà que les notes reproduïdes pel music estiguin més temps en atenuar-se.
El paràmetre Dt és el que representa el temps de Delay de l’estructura.
Aquest efecte funciona adequadament i el seu so és molt semblant als efectes professionals.
És el que té la implementació més senzilla.
4.4 Chorus
Un altre dels efectes més clàssics de la música rock és el Chorus. La seva funció és intentar
simular més d’un instrument realitzant la mateixa peça però tenint en compte les petites
diferencies de volum i afinació què hi ha entre els diferents instruments.
Per fer això, necessitem agafar mostres retardades un 20ms de forma mes o menys aleatòria
i mescla’ls juntament amb el senyal original. Si s’aplica a més petites variacions de volum
en cada línia, s’obté una simulació més real i agradable a l’oïda.
L’estructura emprada en el meu cas és la següent:
E f e c t e s d e s o
25
Figura 4.3 : Diagrama funcional del Chorus
Aquesta estructura simula tres instruments utilitzant dos estructures del Comb Filter, però
en aquest cas es tracta d’un FIR Comb Filter ( Finite Impulse Response), es a dir que l’efecte
de repetició només durarà mentre hi hagi entrada. D’aquesta manera l’estructura es limita a
duplicar el so actual de la guitarra i no tots els sons anteriors, cosa que si feia l’estructura
IIR. Per tal d’implementar els valors aleatoris del LFO què modulen el temps de delay de
cada línia s’ha optat per combinar un parell de taules sinusoïdals què desplacen els
apuntadors amb més o menys aleatorietat per damunt del buffer de mostres. A continuació
es mostra el codi:
#define CHORUS_LENGHT (SAMPLE_ARRAY_LENGHT-10000)
#define HALF_CHORUS_LENGHT (CHORUS_LENGHT/2)
Int16 Chorus(Int16 sample,Int16* delay_array,Int16 PotA,Int16 PotB,Int16
PotC)
{
Int16 output;
float temp;
static float g1,g2; //Gain of each line
static short ac; //Counter of the LFO
static Int16 timec;
static Int16 goal; //LFO frequency adjuster
static int kc = 1000; //Writting pointer
Int16 d1,d2; //Reading pointer
static Int16 PotAz=200,PotBz=200,PotCz=200;
if (PotA != PotAz)
{
temp = ((float)PotA/100 * 564) + 188;
goal = (Int16)temp;
if (goal <=188) goal = 188;
if (goal >=752) goal = 752;
PotAz = PotA;
}
if (PotB != PotBz)
{
g1 = (float)PotB/100 + 0.5;
if (g1 <=0.5) g1 = 0.5;
if (g1 >=1.5) g1 = 1.5;
PotBz = PotB;
}
E f e c t e s d e s o
26
if (PotC != PotCz)
{
g2 = (float)PotC/100 + 0.5;
if (g1 <=0.5) g2 = 0.5;
if (g1 >=1.5) g2 = 1.5;
PotCz = PotC;
}
timec ++;
if (timec >= goal) //This parameter fixes the Freq of the
modulation wave
{
timec = 0;
if (ac < 255) ac++;
else ac = 0;
}
d1 = (float)(sinetable2[ac]+sinetable[ac/2]) * g1;
d1 = kc - d1 - HALF_CHORUS_LENGHT;
d2 = (float)(sinetable2[ac/2]-sinetable[(ac)]) * g2;
d2 = kc - d2;
if (d1<0) d1 += CHORUS_LENGHT ;
if (d2<0) d2 += CHORUS_LENGHT ;
delay_array[kc] = sample;
output = sample/3;
output += (delay_array[d1] /3 );
output += (delay_array[d2] /3 );
if (kc < CHORUS_LENGHT-1) kc++;
else kc = 0;
if ( output > 32767)
{
output = 32767;
}
else if ( output < -32767)
{
output = -32767;
}
return output;
}
Codi 4 : Chorus
Com es pot observar, els dos punters de lectura (d1 i d2) són calculats en cada moment
utilitzant diferents combinacions de les taules sinusoïdals i diferents punts de partida. El d2
es limita a pivotar sobre el punter de escriptura, fet què provoca retards molt curts què
engrandeixen el so. En canvi, el punter d1 agafa el temps màxim possible del buffer, què en
aquest cas té 5000 posicions. Fent un càlcul senzill i sabent que en un segon tenim 48000
mostres, un retard de 2500 mostres, en cas que la combinació de taules sinusoïdals fos 0,
suposa un retard temporal de 50ms.
Mitjançant els potenciòmetres, podem regular tres paràmetres:
Freqüència del LFO
Volum instrument a
Volum instrument b
E f e c t e s d e s o
27
4.5 Flanger
El Flanger, diu la llegenda, fou descobert accidentalment per un enginyer de so què estava
gravant un senyal en dos gravadores de cinta a la vegada i monitoritzant-ho amb uns cascs
on sonaven les dos gravadores a la vegada. Mentre provava de implementar un efecte de
doblat, es va donar compte que petites variacions de velocitat entre ambdues cintes
provocava un so espacial semblant a un motor d’un avio a reacció. D’aquesta manera va
néixer el Flanger.
A nivell teòric i estructural, el Flanger és basa en un chorus, o un chorus és basa en un
Flanger. L’estructura és la mateixa, però en aquest cas, la modulació del LFO que desplaça
el punter de lectura ha de ser completament sinusoïdal. Amés, el punter de lectura s’ha de
situar pivotant sobre la meitat del buffer de mostres. D’aquesta manera, quant el punter es
desplaça en sentit antihorari, es produeix un canvi en l’afinació en sentit descendent. Si gira
en sentit horari o fa de forma ascendent. Aquest efecte sumat a les cancel·lacions de fase què
es produeixen originen el so espacial característic del Flanger.
Figura 4.4 : Diagrama funcional i de Bode del Flander ( FIR Comb Filter)
L’equació què regeix el sistema és la següent:
𝑦(𝑛) = 𝑥(𝑛) · 𝑎1 + 𝑥(𝑛 − 𝐿𝐹𝑂𝑠𝑖𝑛𝑒) · 𝑎2 (4)
A continuació es mostra el codi utilitzat per realitzar el flanger:
Int16 Flanger (Int16 sample, Int16* data,Int16 PotA,Int16 PotB,Int16
PotC)
{
Int16 output;
static Int16 n=0; //Read pointer
static Int16 k=0; //Write pointer
static float gain; //Presence of the effect
static Int16 PotCz=200;
n = modulation (k,PotA,PotB);
E f e c t e s d e s o
28
if (PotC != PotCz)
{
gain = (float)(PotC)/100 + 0.5;
if (gain <=0.5) gain = 0.5;
if (gain >=1.5) gain = 1.5;
PotCz = PotC;
}
data[k] = sample ;
output = (float)data[n] * gain;
output += sample; //Gain increases the presence of the effect
output >>= 1;
if (k < FLANGER_LENGHT-1) k++;
else k = 0;
if ( output > 32767)
{
output = 32767;
}
else if ( output < -32767)
{
output = -32767;
}
return output;
}
Codi 5 : Flanger
En aquest cas, la forma d’actualitzar el punter de lectura és la funció modulation().
Int16 modulation(Int16 k,Int16 PotA,Int16 PotB)
{
Int16 delay;
static Int16 a=0;
static Int16 time = 1;
static Int16 goal;
float temp;
static float g1;
static Int16 PotAz=200,PotBz=200;
if (PotA != PotAz)
{
temp = ((float)PotA/100 * 285) + 91;
goal = (Int16)temp;
if (goal <=91) goal = 91;
if (goal >=376) goal = 376;
PotAz = PotA;
}
if (PotB != PotBz)
{
g1 = (float)PotB/100+ 0.5;
if (g1 <=0.5) g1 = 0.5;
if (g1 >=1.5) g1 = 1.5;
PotBz = PotB;
}
time --;
E f e c t e s d e s o
29
if (time==0)
{
time = goal; //This parameter fixes the freq of
the modulation wave
if (a < 255) a++;
else a = 0;
}
delay = (float)(sinetable[a]- 270)* g1;
delay = k - (HALF_FLANGER_LENGHT - delay); //The mid point of the
table is 100;
if (delay < 0)
{
delay += (FLANGER_LENGHT);
}
return delay;
}
Codi 6 : Modulation Wave Flanger
En aquest efecte tenim tres paràmetres sobre els quals podem actuar. La presencia del efecte,
utilitzant el paràmetre gain amplifiquem el so del flanger sobre la senyal directa. Podem
regular la freqüència del LFO mitjançant el paràmetre goal i finalment, podem incrementar
l’amplitud de l’oscil·lació del LFO per obtenir un efecte més exagerat.
4. 6 Phaser
El Phaser és un dels efectes més curiosos a nivell sonor, tot i que hi ha molta gent què associa
el seu so amb el del Flanger, el funcionament és completament diferent. Com bé indica el
nom, el Phaser és un efecte què es basa en el cancel·lació de fase què hi ha entre la senyal
directa i aquesta passada a traves d’un filtre passa tot. El diagrama de bode del passa tot té
un canvi important de fase en la freqüència central, cosa què fa que si aquesta freqüència es
va canviant, les cancel·lacions de fase provoquen un so molt emblemàtic i futurista.
Hi ha varies aproximacions per estructura a aquest efecte. La primera, consta d’una successió
de tres Notch filters en cascada amb freqüència central oscil·latòria. El so es recombina amb
la senyal original i degut al brusc canvi de fase què es produeix en la freqüència central
s’origina l’efecte. Degut a la utilització dels filtres Notch, és cert que a part de produir-se la
cancel·lació hi ha una atenuació important en les diverses freqüències centrals. Això provoca
que els Phasers encarats amb aquesta estructura tendeixin a ser menys respectuosos amb el
senyal original i resten brillantor al so original de la guitarra.
Figura 4.5: Diagrama funcional del Notch Phaser
E f e c t e s d e s o
30
L’altra estructura, és considera més respectuosa amb el senyal original però no tan efectiva
en el moment d’implementar la cancel·lació de fase. Es tracta de substituït els filtres Notch
per filtres passa tot. D’aquesta manera el senyal no es veu atenuat. S’afegeix però, una línia
de realimentació entre l’entrada del primer filtre i la sortida del tercer per incrementar
l’efecte de cancel·lació de fase.
Figura 4.6 : Diagrama funcional del Allpass Phaser
Tot i la meva perseverança en aquest efecte i ser el que estava més interessat en reproduir
fidelment, no ha aconseguit obtenir un so prou digne com per anomena’l Phaser, he hagut
de reduir la cascada de filtres a solament un ja que degut als errors de precisió dels coeficients
(DSP fixed point) s’acumula molt soroll què no permet a l’efecte resulta agradable.
Els filtres s’han elaborat utilitzant l’estructura paramètrica d’aquests, són filtres de segon
ordre passa tot molt fàcils de calcular, ja que nomes impliquen 2 paràmetres. A continuació
es mostren les equacions i estructura d’aquests.
Figura 4.7 : Diagrama funcional del 2nd order Allpass i les seves equacions
Mitjançant el paràmetre C podem variar el ample de banda del filtre, a menys ample de banda
més brusc serà el canvi de fase. Amb el paràmetre D canviem la freqüència central d’aquests.
D’aquesta manera canviant el paràmetre D de forma sinusoïdal obtindrem l’estructura
necessària pel Phaser.
A continuació mostro el codi utilitzat.
Int16 Phaser(Int16 sample,Int16 PotA,Int16 PotB,Int16 PotC)
E f e c t e s d e s o
31
{
Int16 output;
static Int16 xa[2]; //Memory element for first allpass input
static Int16 ya[2]; //Memory element for first allpass output
static Int16 xb[2]; //Memory element for second allpass input
static Int16 yb[2]; //Memory element for second allpass output
static Int16 xc[2]; //Memory element for third allpass input
static Int16 yc[2]; //Memory element for third allpass output
static Int16 fda=0; //Central freqüenci of first filter
static Int16 fdb=0; //Central freqüenci of second filter
static Int16 fdc=0; //Central freqüenci of third filter
static Int16 fa = 500;
static Int16 fb = 3500;
static Int16 fc = 9500;
static float da,db,dc;
static float c = -0.986220013; //53 Hz bandwidth coef
static short sam_cnt=1;
static Int16 PotAz=200,PotBz=200,PotCz=200;
static short goal;
static float mix;
float temp;
if (PotA != PotAz)
{
temp = ((float)PotA/100 * 20) + 4;
goal = (short)temp;
if (goal <=1) goal = 1;
if (goal >=24) goal = 24;
PotAz = PotA;
}
if (PotB != PotBz)
{
mix = (float)PotB/100 +0.5;
if (mix <=0.5) mix = 0.5;
if (mix >=1.5) mix = 1.5;
PotBz = PotB;
}
sam_cnt--;
if (sam_cnt == 0)
{
sam_cnt = goal; // This parameter controls the freq of the
Phaser modulation wave.
/* First All pass stage */
if (fda == 0)fa += 4;
else fa -= 4;
if (fa >= 3000) // Max Freq of first stage
fda=1;
if (fa <= 500) // Min Freq of first stage
fda = 0;
da = -cos((2 * 3.141592654 * (float)fa )/48000);
}
output = sample + ((float)ya[0] * 0.9);
/*Allpass stage*/
output = allpass(output,xa,ya,c,da);
E f e c t e s d e s o
32
/*Allpass stage*/
//output = allpass(output,xb,yb,c,db); The second and third stage
sounds pretty bad
/*Allpass stage*/
//output = allpass(output,xc,yc,c,dc);
output = sample + ((float)output * mix ) ;
if ( output > 32767)
{
output = 32767;
}
else if ( output < -32767)
{
output = -32767;
}
return output;
}
Codi 7 : Phaser
Degut al mal funcionament, sols he implementat dos tipus de control, el de presència del
efecte, i el de freqüència de la ona moduladora.
Cal destacar que ambdues estructures abans exposades han estat provades i avaluades,
ambdues funcionaven molt justament. Finalment, he decidit agafar la què es podia intuir de
forma més clara com tindria que ser l’efecte i la què dóna un resultat de més qualitat en
directe. Seguiré treballant amb aquest efecte, ja que vull implementa’l amb fidelitat per
satisfacció personal.
4.7 Auto Wah-Wah
El Wah-Wah és un efecte extremadament popular i usat entre els guitarristes. Tothom què
més o menys ha escoltat alguna cosa de música rock ha degut sentir els seus efectes en algun
moment, ja sigui en les parts on el músic interpreta un solo o en ritmes més bàsics. Un clar
exemple és Jimi Hendrix, en la famosa cançó Voodoo Child. Aquell so vocàlic què treu la
guitarra, què sembla que estigui parlant, es degut al Wah-Wah, un efecte amb una estructura
molt semblant a la del Phaser.
Consisteix bàsicament en un filtre passa banda amb freqüència central oscil·latòria.
Normalment la freqüència central es modificada mitjançant un accionament mecànic en
forma de pedal per tal que el músic produeixi el canvi al seu gust. És un efecte què queda
molt be si es va seguint el tempo de la cançó o si es busca una variació més aleatòria que
una ona sinusoïdal.
Per tal de implementar al meu projecte, he decidit fer un Auto Wah-Wah, es a dir, la
freqüència central variaria automàticament mitjançant una ona moduladora sinusoïdal.
L’efecte és totalment funcional tot i això, però és veritat que un auto Wah-Wah no et dóna
la llibertat pròpia d’aquest tipus d’efectes. Els auto Wah-Wah també es comercialitzen en
l’industria, però són pocs els músics què els prefereixen sobre els de accionament manual.
E f e c t e s d e s o
33
Com he comentat l’estructura és molt semblant a la del Phaser, a continuació mostro el
diagrama implementat amb codi.
Figura 4.8 : Diagrama funcional del Wah-Wah
Com es pot observar, el senyal es mesclada amb la mateixa passada pel filtre passa banda,
cosa què produeix una forma en l’espectre de freqüències similar al que es produeix en la
parla humana, per això sembla que la guitarra estigui vocalitzant.
A continuació mostro el codi emprat.
Int16 Auto_Wah_Wah(Int16 sample,Int16 PotA,Int16 PotB,Int16 PotC)
{
Int16 output;
static Int16 xd[2];
static Int16 yd[2];
static Int16 fd=0;
static Int16 f = 1600;
static float d;
static float c = -0.989665051;
static short sam_cnt=1;
static short goal;
static Int16 top;
static float mix;
static Int16 PotAz=200,PotBz=200,PotCz=200;
float temp;
if (PotA != PotAz)
{
temp = ((float)PotA/100 * 23) + 1;
goal = (short)temp;
if (goal <=1) goal = 1;
if (goal >=24) goal = 24;
PotAz = PotA;
}
if (PotB != PotBz)
{
mix = (float)PotB/100;
if (mix <=0) mix = 0;
if (mix >=1) mix = 1;
PotBz = PotB;
}
if (PotC != PotCz)
{
temp = ((float)PotC/100 * 2000);
top = (Int16)temp;
if (top <=0) top = 0;
E f e c t e s d e s o
34
if (top >=2000) top = 2000;
PotCz = PotC;
}
sam_cnt--;
if (sam_cnt == 0)
{
sam_cnt = goal; // This parameter controls the freq of the wah
modulation
if (fd == 0)f += 4;
else f -= 4;
if (f >= (3000 + top))
fd=1;
if (f <= (500 + top))
fd = 0;
d = -cos((2*3.141592654 * (float)f )/48000); //This line
changes the bandass center frequency
}
/*Bandpass stage*/
output = allpass(sample,xd,yd,c,d);
output = (sample - output);
/*Wah-Wah Stage*/
output = (sample * (1-mix)) + (output * mix);
if ( output > 32767)
{
output = 32767;
}
else if ( output < -32767)
{
output = -32767;
}
return output;
}
Codi 8 : Auto Wah-Wah
Per tal de implementar el filtre passa banda, s’ha utilitzat una estructura paramètrica
d’aquests aproximada mitjançant un filtre passa tot, a continuació en mostro el diagrama.
Figura 4.9 : Diagrama funcional del filtre passabanda
La funció A(z) pertany a l’estructura del filtre passa tot implementada anteriorment en el
Phaser. En funció del sumatori obtindrem un passa banda o un talla banda.
E f e c t e s d e s o
35
Com es pot observar en el codi, aquest efecte té tres paràmetres regulables:
Freqüència d’oscil·lació del LFO (mitjançant el paràmetre goal)
Rang de freqüències del LFO (mitjançant el paràmetre top)
Presencia del efecte (mitjançant el paràmetre mix)
Tot i ser casi idèntic al Phaser i com he comentat anteriorment, el Phaser no sona bé, aquest
efecte sona increïblement bé. Cosa què hem fa més incomprensible el problema amb el
Phaser.
4.8 Equalitzador
Com a últim efecte tenim l’equalitzador, consta bàsicament de tres filtres implementats per
destacar tres bandes de freqüència. La banda dels greus, els mitjos i els aguts. Per tal
d’implementar aquest efecte s’ha seguit el disseny recomanat en la literatura consistent en
filtres del tipus Shelving per les bandes greus i agudes, i un filtre Peak per la banda dels
mitjos.
Figura 4.10 : Diagrama del equalitzador
Els filtres s’han implementat amb les formes paramètriques d’aquests. S’han calculat els
coeficients i s’han inicialitzat de tal manera que l’efecte nomes consisteixi en llegir diferents
posicions d’una estructura de dades. Així estalviem temps de còmput al DSP. S’han definit
9 posicions per cada filtre, representat diferents guanys (-12dB, -9dB, -6dB, -3dB, 0dB,
+3dB,+ 6dB, +9dB, +12dB). Les freqüències centrals per a cada un són les següents:
Low Shelving 800 Hz
Mid Peak 2100 Hz
High Peak 5000 Hz
A continuació es mostren les estructures utilitzades:
E f e c t e s d e s o
36
Figura 4.11 : Diagrama del 1st order LF/HF Shelving filter Figura 4.12 : Diagrama del Peak filter
A continuació mostro el codi emprat per tal de simular aquest efecte.
s1 = ShelvingHL (LOW_FREQ,l_in,l_out,sample,l1,l2); //Low Equ
s2 = Peak(sample,m1,m2); //Mid Equ
s3 = ShelvingHL (HIGH_FREQ,h_in,h_out,sample,h1,h2); //High Equ
output = (s1 + s2 + s3)/3;
Codi 9 : Equalizer
L’estructura de cada filtre per separat és la següent:
Shelving
Int16 ShelvingHL (char HL,Int16 *last_input,Int16 *last_output, Int16
sample,float a, float H)
{
long temp;
Int16 output;
temp = (long)sample * a + (long)*last_input + (long)*last_output * (-a);
//First-order allpass A(z)
temp >>= 15;
*last_output = (Int16)temp;
*last_input = sample;
output = ( sample + (Int16)temp * HL ) * (H / 2) + sample; //First-
order low/high-freq shelving
return output;
}
Codi 10 : Shelving filter
E f e c t e s d e s o
37
Peak
Int16 Peak(Int16 sample,float a,float H)
{
static Int16 last_input[2];
static Int16 last_output[2];
Int16 output;
long temp;
temp = ((long)sample * -a) + ( (long)last_input[0] * D*(1-a)) +
(long)last_input[1] + ((long)last_output[0] * -D*(1-a)) +
((long)last_output[1] * a);
temp >>= 15;
last_output[1] = last_output[0];
last_output[0] = (Int16)temp;
last_input[1] = last_input[0];
last_input[0] = sample;
output = (sample - (Int16)temp)*(H/2) + sample;
return output;
}
Codi 11 : Peak filter
C o d i f u n c i o n a l
38
5. Codi funcional
Per tal d’implementar tots el efectes s’ha hagut d’incloure molt codi de suport a aquests, tant
per inicialitza perifèrics com per a crear l’estructura de la màquina d’estat.
El codi principalment té dues parts, la primera consisteix en la inicialització de tots els
perifèrics i de valors necessaris. A continuació apunto les funcions cridades.
EZDSP5535_init(); //Connects the clock to the eZdsp board peripherals
EZDSP5535_I2C_init( ); //Initializes the I2C bus and configures it
GPIO_IO(); //Initializes the GPIO and sets the directions
of each one
sar_ini(SarObj,SarHandle); //Initializes the SAR module and
configures it
Audio_Set(); //Initializes the Audio Codec
set_sampling_frequency_and_gain(SAMPLES_PER_SECOND,GAIN_IN_dB); //Sets
the sampling frequency and the output gain of the audio codec.
EZDSP5535_I2S_init( ); //Initializes the I2S bus
EQ_init (&Eq); //Initializes the EQ parameters structure
sample_array_clear(sample_array); //Clears the sample array
Codi 12 :Main - Initialitzations
Totes les funcions basades en perifèrics, han estat implementades mitjançant les llibreries de
Texas Instruments anomenades CSL (chip suport library). Contenen tota la API necessària
per gestionar i configurar els perifèrics.
La segona part, és un bucle infinit en el qual té lloc la màquina d’estats. Bàsicament el que
fa és llegir mostra, en funció de l’estat de la interfície realitzar un efecte i tirar la mostra.
Cada 48000 mostres la màquina torna a llegir la interfície física i d’aquesta manera, canviar
l’estat. A continuació es mostra un diagrama del seu funcionament.
Figura 5.1 : Diagrama cíclic
El codi per realitzar aquesta maniobra és el següent:
Llegir Guitarra
Aplicar efecte
Escriure sortida
If (mostra == 48000) Llegir
interficia
C o d i f u n c i o n a l
39
while(1)
{
for ( sec = 0 ; sec < 5 ; sec++ )
{
Read_Interface(&Fx,SarHandle); //Gets the state from the interface
(Pots,toggle, rotatory switch)
for ( msec = 0 ; msec < 1000 ; msec++ )
{
for ( smpl = 0 ; smpl < 48 ; smpl++ )
{
/*Get the signal from the guitar*/
get_guitar(&left_input);
switch (Fx.State)
{
case 0: //Clean channel + Equalizer
left_output = Clean(left_input);
left_output =
three_band_equ(left_output,&Eq,Fx.PotA1,Fx.PotB1,Fx.PotC1);
left_output *= Fx.Clean_Vol;
break;
case 1: //Clean channel + Delay
left_output = Clean(left_input);
left_output = Delay_IIR
(left_output,sample_array,Fx.PotA1,Fx.PotB1,Fx.PotC1);
left_output *= Fx.Clean_Vol;
break;
case 2: //Clean channel + Chorus
left_output = Clean(left_input);
left_output =
Chorus(left_output,sample_array,Fx.PotA1,Fx.PotB1,Fx.PotC1);
left_output *= Fx.Clean_Vol;
break;
case 3: //Clean channel + Flanger
left_output = Clean(left_input);
left_output = Flanger
(left_output,sample_array,Fx.PotA1,Fx.PotB1,Fx.PotC1);
left_output *= Fx.Clean_Vol;
break;
case 4: //Clean channel + Phaser
left_output = Clean(left_input);
left_output =
Phaser(left_output,Fx.PotA1,Fx.PotB1,Fx.PotC1);
left_output *= Fx.Clean_Vol;
break;
case 5: //Clean channel + Auto Wah-Wah
left_output = Clean(left_input);
left_output =
Auto_Wah_Wah(left_output,Fx.PotA1,Fx.PotB1,Fx.PotC1);
left_output *= Fx.Clean_Vol;
C o d i f u n c i o n a l
40
break;
case 8: //Overdrive channel + Equalizer
left_output = Overdrive (left_input);
left_output =
three_band_equ(left_output,&Eq,Fx.PotA2,Fx.PotB2,Fx.PotC2);
left_output *= Fx.Dirt_Vol;
break;
case 9: //Overdrive channel + Delay
left_output = Overdrive (left_input);
left_output = Delay_IIR
(left_output,sample_array,Fx.PotA2,Fx.PotB2,Fx.PotC2);
left_output *= Fx.Dirt_Vol;
break;
case 10: //Overdrive channel + Chorus
left_output = Overdrive (left_output);
left_output =
Chorus(left_output,sample_array,Fx.PotA2,Fx.PotB2,Fx.PotC2);
left_output *= Fx.Dirt_Vol;
break;
case 11: //Overdrive channel + Flanger
left_output = Overdrive (left_output);
left_output =
Flanger(left_output,sample_array,Fx.PotA2,Fx.PotB2,Fx.PotC2);
left_output *= Fx.Dirt_Vol;
break;
case 12: //Overdrive channel + Phaser
left_output = Overdrive (left_input);
left_output =
Phaser(left_output,Fx.PotA2,Fx.PotB2,Fx.PotC2);
left_output *= Fx.Dirt_Vol;
break;
case 13: //Overdrive channel + Auto Wah-Wah
left_output = Overdrive (left_input);
left_output =
Auto_Wah_Wah(left_output,Fx.PotA2,Fx.PotB2,Fx.PotC2);
left_output *= Fx.Dirt_Vol;
break;
}
/*Throw guitar signal through line*/
throw_guitar(left_output);
}
}
}
};
Codi 13 :Main – State Machine
La funció Read_Interface és l’encarregada d’obtenir tota la informació de la interfície, és la
què manipula els ports GPIO per tal de commutar el multiplexor i de llegir els valors dels
ports analògics GPAIN mitjançant el mòdul SAR.
C o d i f u n c i o n a l
41
void Read_Interface(Shape* Fx,CSL_SarHandleObj **SarHandle)
{
Int16 temp = 0;
float temf = 0;
Int16 toggle_temp=0;
/*Read the Toggle Switch*/
toggle_temp = EZDSP5535_GPIO_getInput(14);
EZDSP5535_waitusec( 50 );
toggle_temp += EZDSP5535_GPIO_getInput(14);
EZDSP5535_waitusec( 50 );
toggle_temp += EZDSP5535_GPIO_getInput(14);
EZDSP5535_waitusec( 50 );
toggle_temp += EZDSP5535_GPIO_getInput(14);
EZDSP5535_waitusec( 50 );
toggle_temp += EZDSP5535_GPIO_getInput(14);
EZDSP5535_waitusec( 50 );
toggle_temp += EZDSP5535_GPIO_getInput(14);
if (toggle_temp==6) Fx->State = 0;
else Fx->State = 8;
/*Read the 6 positions rotatory switch*/
temp = Read_SAR(SarHandle[0],1);
if (temp == 112) Fx->State += 5;
else if (temp == 67) Fx->State += 4;
else if (temp == 56) Fx->State += 3;
else if (temp == 48) Fx->State += 2;
else if (temp == 33) Fx->State += 1;
else if (temp == 0) Fx->State += 0;
temp = 0;
/*Read the multiplexed pots array*/
EZDSP5535_GPIO_setOutput( GPIO12, 1 ); //Enable multiplexor
EZDSP5535_GPIO_setOutput( GPIO15, 0 );
EZDSP5535_GPIO_setOutput( GPIO17, 0 );
temf = (float)Read_SAR(SarHandle[1],4);
Fx->Clean_Vol = temf/538;
temf = Read_SAR(SarHandle[2],5);
Fx->PotA2 = (Int16)(temf*100/538);
EZDSP5535_GPIO_setOutput( GPIO15, 1 );
EZDSP5535_GPIO_setOutput( GPIO17, 0 );
temf = Read_SAR(SarHandle[1],4);
Fx->PotB1 = (Int16)(temf*100/538);
temf = Read_SAR(SarHandle[2],5);
Fx->PotB2 = (Int16)(temf*100/538);
EZDSP5535_GPIO_setOutput( GPIO15, 0 );
EZDSP5535_GPIO_setOutput( GPIO17, 1 );
temf = Read_SAR(SarHandle[1],4);
Fx->PotA1 = (Int16)(temf*100/538);
temf = (float)Read_SAR(SarHandle[2],5);
C o d i f u n c i o n a l
42
Fx->Dirt_Vol = (temf/538);
EZDSP5535_GPIO_setOutput( GPIO15, 1 );
EZDSP5535_GPIO_setOutput( GPIO17, 1 );
temf = Read_SAR(SarHandle[1],4);
Fx->PotC1= (Int16)(temf*100/538);
temf = Read_SAR(SarHandle[2],5);
Fx->PotC2 = (Int16)(temf*100/538);
EZDSP5535_GPIO_setOutput( GPIO12, 0); //Disable multiplexor
temp = 0;
if ((Fx->PotA1 >= 0) & (Fx->PotA1 <= 9)) Fx->PotA1 = 0;
else if ((Fx->PotA1 >= 10) & (Fx->PotA1 <= 19)) Fx->PotA1 = 10;
else if ((Fx->PotA1 >= 20) & (Fx->PotA1 <= 29)) Fx->PotA1 = 20;
else if ((Fx->PotA1 >= 30) & (Fx->PotA1 <= 39)) Fx->PotA1 = 30;
else if ((Fx->PotA1 >= 40) & (Fx->PotA1 <= 49)) Fx->PotA1 = 40;
else if ((Fx->PotA1 >= 50) & (Fx->PotA1 <= 59)) Fx->PotA1 = 50;
else if ((Fx->PotA1 >= 60) & (Fx->PotA1 <= 69)) Fx->PotA1 = 60;
else if ((Fx->PotA1 >= 70) & (Fx->PotA1 <= 79)) Fx->PotA1 = 70;
else if ((Fx->PotA1 >= 80) & (Fx->PotA1 <= 89)) Fx->PotA1 = 80;
else if ((Fx->PotA1 >= 90) & (Fx->PotA1 <= 99)) Fx->PotA1 = 90;
else if (Fx->PotA1 >= 100) Fx->PotA1 = 100;
if ((Fx->PotB1 >= 0) & (Fx->PotB1 <= 9)) Fx->PotB1 = 0;
else if ((Fx->PotB1 >= 10) & (Fx->PotB1 <= 19)) Fx->PotB1 = 10;
else if ((Fx->PotB1 >= 20) & (Fx->PotB1 <= 29)) Fx->PotB1 = 20;
else if ((Fx->PotB1 >= 30) & (Fx->PotB1 <= 39)) Fx->PotB1 = 30;
else if ((Fx->PotB1 >= 40) & (Fx->PotB1 <= 49)) Fx->PotB1 = 40;
else if ((Fx->PotB1 >= 50) & (Fx->PotB1 <= 59)) Fx->PotB1 = 50;
else if ((Fx->PotB1 >= 60) & (Fx->PotB1 <= 69)) Fx->PotB1 = 60;
else if ((Fx->PotB1 >= 70) & (Fx->PotB1 <= 79)) Fx->PotB1 = 70;
else if ((Fx->PotB1 >= 80) & (Fx->PotB1 <= 89)) Fx->PotB1 = 80;
else if ((Fx->PotB1 >= 90) & (Fx->PotB1 <= 99)) Fx->PotB1 = 90;
else if (Fx->PotB1 >= 100) Fx->PotB1 = 100;
if ((Fx->PotC1 >= 0) & (Fx->PotC1 <= 9)) Fx->PotC1 = 0;
else if ((Fx->PotC1 >= 10) & (Fx->PotC1 <= 19)) Fx->PotC1 = 10;
else if ((Fx->PotC1 >= 20) & (Fx->PotC1 <= 29)) Fx->PotC1 = 20;
else if ((Fx->PotC1 >= 30) & (Fx->PotC1 <= 39)) Fx->PotC1 = 30;
else if ((Fx->PotC1 >= 40) & (Fx->PotC1 <= 49)) Fx->PotC1 = 40;
else if ((Fx->PotC1 >= 50) & (Fx->PotC1 <= 59)) Fx->PotC1 = 50;
else if ((Fx->PotC1 >= 60) & (Fx->PotC1 <= 69)) Fx->PotC1 = 60;
else if ((Fx->PotC1 >= 70) & (Fx->PotC1 <= 79)) Fx->PotC1 = 70;
else if ((Fx->PotC1 >= 80) & (Fx->PotC1 <= 89)) Fx->PotC1 = 80;
else if ((Fx->PotC1 >= 90) & (Fx->PotC1 <= 99)) Fx->PotC1 = 90;
else if (Fx->PotC1 >= 100) Fx->PotC1 = 100;
if ((Fx->PotA2 >= 0) & (Fx->PotA2 <= 9)) Fx->PotA2 = 0;
else if ((Fx->PotA2 >= 10) & (Fx->PotA2 <= 19)) Fx->PotA2 = 10;
else if ((Fx->PotA2 >= 20) & (Fx->PotA2 <= 29)) Fx->PotA2 = 20;
else if ((Fx->PotA2 >= 30) & (Fx->PotA2 <= 39)) Fx->PotA2 = 30;
else if ((Fx->PotA2 >= 40) & (Fx->PotA2 <= 49)) Fx->PotA2 = 40;
else if ((Fx->PotA2 >= 50) & (Fx->PotA2 <= 59)) Fx->PotA2 = 50;
else if ((Fx->PotA2 >= 60) & (Fx->PotA2 <= 69)) Fx->PotA2 = 60;
else if ((Fx->PotA2 >= 70) & (Fx->PotA2 <= 79)) Fx->PotA2 = 70;
else if ((Fx->PotA2 >= 80) & (Fx->PotA2 <= 89)) Fx->PotA2 = 80;
else if ((Fx->PotA2 >= 90) & (Fx->PotA2 <= 99)) Fx->PotA2 = 90;
C o d i f u n c i o n a l
43
else if (Fx->PotA2 >= 100) Fx->PotA2 = 100;
if ((Fx->PotB2 >= 0) & (Fx->PotB2 <= 9)) Fx->PotB2 = 0;
else if ((Fx->PotB2 >= 10) & (Fx->PotB2 <= 19)) Fx->PotB2 = 10;
else if ((Fx->PotB2 >= 20) & (Fx->PotB2 <= 29)) Fx->PotB2 = 20;
else if ((Fx->PotB2 >= 30) & (Fx->PotB2 <= 39)) Fx->PotB2 = 30;
else if ((Fx->PotB2 >= 40) & (Fx->PotB2 <= 49)) Fx->PotB2 = 40;
else if ((Fx->PotB2 >= 50) & (Fx->PotB2 <= 59)) Fx->PotB2 = 50;
else if ((Fx->PotB2 >= 60) & (Fx->PotB2 <= 69)) Fx->PotB2 = 60;
else if ((Fx->PotB2 >= 70) & (Fx->PotB2 <= 79)) Fx->PotB2 = 70;
else if ((Fx->PotB2 >= 80) & (Fx->PotB2 <= 89)) Fx->PotB2 = 80;
else if ((Fx->PotB2 >= 90) & (Fx->PotB2 <= 99)) Fx->PotB2 = 90;
else if (Fx->PotB2 >= 100) Fx->PotB2 = 100;
if ((Fx->PotC2 >= 0) & (Fx->PotC2 <= 9)) Fx->PotC2 = 0;
else if ((Fx->PotC2 >= 10) & (Fx->PotC2 <= 19)) Fx->PotC2 = 10;
else if ((Fx->PotC2 >= 20) & (Fx->PotC2 <= 29)) Fx->PotC2 = 20;
else if ((Fx->PotC2 >= 30) & (Fx->PotC2 <= 39)) Fx->PotC2 = 30;
else if ((Fx->PotC2 >= 40) & (Fx->PotC2 <= 49)) Fx->PotC2 = 40;
else if ((Fx->PotC2 >= 50) & (Fx->PotC2 <= 59)) Fx->PotC2 = 50;
else if ((Fx->PotC2 >= 60) & (Fx->PotC2 <= 69)) Fx->PotC2 = 60;
else if ((Fx->PotC2 >= 70) & (Fx->PotC2 <= 79)) Fx->PotC2 = 70;
else if ((Fx->PotC2 >= 80) & (Fx->PotC2 <= 89)) Fx->PotC2 = 80;
else if ((Fx->PotC2 >= 90) & (Fx->PotC2 <= 99)) Fx->PotC2 = 90;
else if (Fx->PotC2 >= 100) Fx->PotC2 = 100;
return;
}
Codi 13 : Interface reading function
La funció va llegint els valors i els associa a l’estructura creada per emmagatzemar aquests,
la funció està pensada per treure valors redons com es pot observar en la part final d’aquesta.
Els potenciòmetres referents al volum dels canals s’obtenen en format float ja que es pretén
multiplicar les mostres directament per aquests valors.
Finalment, les funcions get_guitar i throw_guitar són simplement part de l’API. En l’interior
hi ha la crida del mòdul I2S per tal de traslladar les mostres cap a al CPU. Es va provar de
realitzar aquesta funció mitjançant els mòduls de DMA però no me’n vaig sortir i vaig
decidir fer-ho per lectures directes, tot i que no és una opció massa optima.
C o n c l u s i o n s
44
6. Conclusions
Abans de preparar a aquest projecte era un simple aficionat als efectes d’àudio. Tot i fascinar-
me completament el seu funcionament mai m’havia atrevit a enfronta’m al seu disseny o
funcionament, principalment per respecte i per considera’ls massa complicats pel meu nivell.
Quant vaig començar la carrera ja tenia clar que un dels objectius d’aquesta era assolir els
coneixements suficients com per comprendre aquestes estructures i poder “jugar” amb elles.
Em satisfà plenament veurem capaç de fer-ho i haver-ho fet. Objectiu complert.
És cert que el funcionament final del projecte no és del tot el que jo esperava, potser en part
degut a les meves ganes de fer massa coses o al fet de voler obtenir uns resultats molt
professionals. La veritat és que la literatura dels efectes d’àudio és molt reservada i molt
generalista, m’explico. És molt fàcil trobar les estructures més o menys bàsiques i la
informació què les contextualitza amb el món de la música. Però la implementació d’aquests
i sobretot, aquelles petites o grans coses què fan d’un efecte un producte per comercialitzar,
estan gelosament guardades per aquells què les desenvolupen, com és obvi que així ha de
ser (o no).
Estic molt content del resultat, m’he hagut d’enfrontar a un món totalment desconegut,
l’electrònica d’àudio i tot el relacionat amb els DSP. No diré que a estat fàcil, perquè en
molts moments m’he trobat perdut i he requerit de molta lectura en debats virtuals sobre la
temàtica. Però si que ha estat molt gratificant. A hores d’ara, quant m’assec a tocar la guitarra
i activo els efectes què he anat adquirint durant els anys, els miro d’una altra manera. Puc
visualitzar els diagrames interns i funcionalitats pròpies de cada un, cosa que m’ha permès
tenir un control sobre ells molt més gran, apart de les gratificants converses què puc establir
ara amb altres col·legues del gremi de la música sobre l’estructura d’aquests.
També he trobat extremadament interesant el món dels DSP. Un component sobre el qual
no havia sentit mai a parlar i que m’ha fascinat tant per les seves capacitats com pel gran
nombre de gent què treballa amb ells i n’escriu referencies a la xarxa. Realment m’he ficat
una mica la pell d’un veritable enginyer mentre buscava informació sobre el seu
funcionament.
Puc afirmar que aquest projecte m’ha fet una mica més gran com a enginyer, i sobretot m’ha
servit com a reforç personal, ja que tots els problemes què m’he trobat els he resolt pel meu
compte. Crec que estic preparat per enfronta’m a qualsevol cosa desconeguda amb certa
comoditat i paciència.
Finalment, m’agradaria apuntar que aquest projecte solament és el començament. Seguiré
treballant sobre ell per tal de desenvolupar efectes conegut i si puc, desconeguts. Ho
considero una “joguina” increïblement brillant, què em permetrà aprendre molt més sobre el
món de l’àudio. També espero utilitzar-la en directe en algun concert, serà la meva caixa
d’efectes única i màgica que potser em dóna un renom interessant dins del gremi.
B i b l i o g r a f i a
45
7. Bibliografia
[1] Udo Zolzer, DAFX – Digital Audio Effects, John Wiley & Sons, Inc , 2002.
[2] Texas Instruments , TMS320C5535/34/33/32 Ultra-‐‑Low Power DSP Technical Reference Manual, 2012
http://www.ti.com/lit/ug/spruh87c/spruh87c.pdf
[3] Texas Instruments ,Ultra Low Power Stereo Audio Codec,2012
http://www.ti.com/lit/ds/symlink/tlv320aic3204.pdf
[4] Vishay Siliconix, 8-Ch/Dual 4-Ch High-Performance CMOS Analog Multiplexers, 2016
http://www.vishay.com/docs/70062/dg408.pdf
[5] Analog Devices, Using The Low Cost, High Performance ADSP-21065L Digital
Signal Processor For Digital Audio Applications,1998
http://dsp-book.narod.ru/soundproc.pdf
[6] Texas Instruments, How to Create Delay-based Audio Effects on the
TMS320C672x DSP,2005
http://www.ti.com/lit/an/spraaa5/spraaa5.pdf