WinAmp Plug-in – 2. část - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



Delphi

WinAmp Plug-in – 2. část

winamp

3. března 2003, 00.00 | V dnešním pokračování našeho malého seriálu o tvorbě plug-in souboru se pokusím splnit sliby, které jsem dal na konci prvního dílu, a to, že vysvětlím bližší význam některých konstant a potřebných funkcí, s kterými jsme pracovali již minule, aniž bychom o nich něco věděli. Naučíme se taky jak získat výstupní data z Winampu a jak je správně využít.

V dnešním pokračování našeho malého seriálu o tvorbě plug-in souboru se pokusím splnit sliby, které jsem dal na konci prvního dílu, a to, že vysvětlím bližší význam některých konstant a potřebných funkcí, s kterými jsme pracovali již minule, aniž bychom o nich něco věděli. Naučíme se taky jak získat výstupní data z Winampu a jak je správně využít. Spolu s tím si nakonec ukážeme jeden z možných příkladů, který se obvykle využívá při zobrazování hudebních spekter.

Základní struktura modulu a její inicializace

Začnu jak jinak než od samého začátku. Pro některé z Vás zvídavějších to bude jistě nošení dříví do lesa, ale najdou se i takoví, kterým všechno není jasné na první pohled. Minule jsme si vytvořili pomocný soubor winamp.pas a v něm jsme deklarovali typ TWinampVisModule. Tento typ nám určuje strukturu vybraného modulu v našem plug-inu. Při výběru v menu Vizualizace programu WinAmp je v pravé dolní části obrazovky ComboBox právě s výběrem našich modulů. Všechny moduly, které deklarujeme, se nám tam poté objeví a uživatel je schopen si jeden z nich zvolit. Přiřazení vybraného modulu nám provádí funkce getModule, kterou jsme vysvětlili již minule. Typ modulu obsahuje mnoho konstant, které je nutné správně pochopit. Z těch nejdůležitějších to jsou:

Description – je typu PChar a určuje název (případně krátký popis) modulu
LatencyMs – je údaj v ms (milisekunda), udávající zpoždění reakce na příchozí data. Standardní hodnota je 0ms a nenapadl mě žádný smysluplný význam využití.
DelayMs - Opět čas v ms, který je ale velice důležitý, protože říká modulu, jak často má požadovat po WinAmpu další data. Udává vlastně čas mezi vykreslením dalšího obrazu spektra. Její volbu je nutné dobře zvážit, protože malá hodnota by mohla způsobit tak rychlé kreslení, že by obraz nebyl zřetelný a naopak hodnota velká způsobí, že obraz nebude měněn plynule a bude vypadat jakoby se sekal. Optimální hodnotou na rychlejších počítačích je 25ms.
SpectrumNch a WaveformNch – tyto hodnoty jsou vcelku podobné. Obě udávají počet zvukových stop, které chceme přijímat. Jelikož zvuk může být buďto mono nebo stereo, jsou jejich typické hodnoty logicky 0,1 nebo 2. Data se potom liší podle toho, jestli je čteme z spectrumData nebo z waveformData. Najednou je dobré přijímat data jen z jednoho typu zdroje, tzn. druhý má hodnotu 0.
WaveformData a SpectrumData – Jedny z nejdůležitějších vlastností modulu! Pole hodnot hlasitostí aktuálně přehrávané zvukové stopy rozdělené podle jednotlivých frekvencí vzestupně. Tzn. hodnoty kolem 60Hz jsou v poli uloženy na nejnižších indexech a naopak zvuky s frekvencí 16KHz jsou na konci pole. Nemyslete si ale, ze stačí přečíst hodnoty pole a jen je nakreslit do spojitého grafu, neboť by výsledek nevypadal asi podle Vašich představ. Musíte mít na mysli, že jsou v jednom poli data z 2 zvykových kanálů (levý a pravý). V poli WaveformData jsou hodnoty pro spojitý graf (tzn. zvuk o jedné harmonické by vypadal jako sinusovka). V poli SpectrumData jsou hodnoty pro sloupcový graf známý z klasického WinAmpu. Příklad zpracování si ukážeme později.

Ostatní hodnoty nemají pro nás žádný podstatný význam a proto jejich nastavením na 0 zajistíme defaultní hodnoty. Některé z nich však budeme ještě potřebovat.
Dále následují názvy funkcí pro konfiguraci, inicializaci, vykreslení a ukončení modulu, které již dobře známe z minula. Pokud se funkce Init, Config a Quit neliší, můžeme použít stejné u obou modulů.

Dalším, již méně podstatným typem, je TwinampVisHeader, který nám pouze definuje jméno (hodnota Description typu PChar) a verzi (hodnota Version typu Integer) našeho Plug-inu, které se zobrazí v programu WinAmp a říká, která funkce je zodpovědná za volbu modulu (hodnota GetMoule). Hodnotu verze plug-inu je vhodné mít definovanou jako konstantu také v externím souboru, abychom ji někde nechtěně nezměnili a nedošlo ke kolizím čísel verzí.

Grafický výstup modulu:

Teď, když už máme správně nastavené oba moduly a chápeme jejich funkce, můžeme se nyní nějakým způsobem pokusit získané data zobrazit. Způsobů zobrazení je nespočetně mnoho, a proto také vzniká spousta nových plug-inů. Já se Vám pokusím přiblížit jeden z těch nejzákladnějších.
Jako první se podíváme na zpracování dat z pole WaveformData. Jedná se o spojitý graf. Abychom dosáhli požadované spojitosti budeme používat funkce LineTo z předchozího do aktuálního bodu. Pokud bychom jen kreslili body, byl by výstup velmi nezřetelný. My tedy budeme předpokládat lineární aproximaci mezi každým bodem. Při psaní funkce Tender musíme být obzvlášť obezřetní. Musíme mít namysli, že se funkce volá (v našem případě) každých 25ms. První věc u každého snímku je prvotní vymazání obrazovky, aby se v jednu chvíli nakreslilo pouze jedno aktuální spektrum. Kdybychom to neudělali, spektra by se kreslily stále na sebe a obrazovka by za malou chvíli zčernala. Vymazání provedeme např. nakreslením jednobarevného obdélníka přes celou oblast. Teď již jen pro všechny prvky pole WaveformData nakreslíme čáru z bodu předchozího do bodu následujícího. Jelikož má pole WaveformData prvky typu Char (tj. císla 0-255), musíme získané hodnoty přepočítat. A to tak, ze kladná část spektra je uložena v hodnotách 0-128 a záporná část v hodnotách 129-255. Když tohle víme, nebrání nám již nic v napsání cyklu:

for y:=0 to this_mod.nCh-1 do
begin
last:=@this_mod^.waveformData[y,0];

if last^>128 then
last^:=last^-128
 else
last^:=last^+128;

bmp.canvas.MoveTo(0,last^);
     for x:=1 to 288 do
        begin
        this:=@this_mod^.waveformData[y,x];
        if (this^>128) then
         begin
         this^:=this^-128;
         end
        else
         begin
         this^:=this^+128;
         end;
        bmp.Canvas.LineTo(x,this^);
        end;
  end;

V něm se vyskytuje proměnná this_mod.nCh, která udává počet zvukových kanálů (1-mono, 2- stereo) a my ji používáme při indexaci pole waveformData, které je dvourozměrné. První rozměr je požadovaný kanál, druhý je x-ová pozice našeho spektra. Po vykreslení spektra jsem přes graf nakreslil ještě středovou osu. Na začátku jsem zapomněl ještě na jednu věc, a to, že vše se kreslí do virtuální bitmapy, která je na konci funkce Tender zkopírována do zobrazovaného okna. Tímto se docílí velkého zrychlení celého procesu a zamezení nepříjemného blikání, jelikož se do video-paměti zapisuje jen jednou.
Možná některé z vás udiví, proč jsem použil data pouze do hodnoty 288? Vysvětlení již v podstatě padlo. Je zcela na programátorovi jak grafický výstup udělá. Pokud někteří čtenáři nerozumí některým značkám v kódu jako ^ a @, tak vězte, že se jedná o pointerovou aritmetiku, jejíž vysvětlení je nad rámec tohoto článku. Snad jen připomenu, že operátor ^ převádí ukazatel na hodnotu a @ naopak.


Výsledek modulu 1

Jako druhý příklad grafického výstupu vytvořený z hodnot pole SpectrumData uvádím tento příklad:


for y:=0 to this_mod.nCh do
 for x:=1 to 288 do
  begin
    b:=@this_mod^.spectrumData[y,x];
    b^:=b^*3; //potlačení výšek
    if b^>128 then b^:=128;
    case (x mod 5) of
    0: x1:=128 -b^;
    1: x2:=128 -b^;
    2: x3:=128 -b^;
    3: x4:=128 -b^;
    4: x5:=128 -b^;
    end;
    if x mod 5=0 then
    begin
    z:=x1+x2+x3+x4+x5;
    z:=trunc(z div 5);
    bmp.canvas.FillRect(rect(x-5,z,x,128));
    end;
  end;

bmp.canvas.Pen.Color:=clred;
bmp.canvas.MoveTo(0,128);
bmp.canvas.LineTo(bmp.width,128);
bmp.canvas.Brush.Color:=clwhite;
bmp.Canvas.TextOut(0,0,inttostr(this_mod.nCh));
form1.Canvas.Draw(0,0,bmp);



Výsledek modulu 2

Opět i tady platí, že způsob zpracování je jen na programátorovi a já jsem spojil sousedních 5 dat a ty zprůměrňoval a vykreslil ve tvaru sloupce. Taky jsem nakreslil oba kanály přes sebe stejně jako v prvním případě s tím rozdílem, že zde se překrývají a jde vidět jen vyšší z nich. Možností grafických výstupů jsou nepřeberné a velice relativní. Nakonec jsem ještě uvedl příklad zobrazení počtu přehrávaných kanálů, který jsem vypsal do levého horního rohu. Pokud ve funkci TextOut změníte nCh za sRate, bude se vypisovat vzorkovací frekvence přehrávané skladby. Sami můžete vyzkoušet rozdíl mezi skladbou mono a stereo.
Tímto bych dnešní díl ukončil. Příště si snad ukážeme zdařilejší grafický výstup za pomocí nedávno recenzované grafické knihovny. Chtěl bych se omluvit, za horší čitelnost článku, neboť je složité popsat význam příkazů, které spolu všestranně souvisí. Je dobré si s nimi chvíli hrát a osvojit si jejich funkce. Byl bych velice rád, jestli se podaří někomu z Vás napsat nějaký pěkný plug-in, aby mi jeho ukázku zaslal emailem, případně jsem ochoten cokoli vysvětlit a poradit v diskuzi. A pro ty zvídavější mám závěrečnou otázku: Jak myslíte, že zjistíte název právě přehrávané skladby?
Kompletní zdrojové kódy jsou ke stažení ZDE.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Delphi  

 » Rubriky  » Windows  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: