Zobrazit předchozí téma :: Zobrazit následující téma |
Autor |
Zpráva |
rotacak
Založen: 19. 02. 2009 Příspěvky: 28
|
Zaslal: 19. únor 2009, 20:46:19 Předmět: Synchronizace muziky (BPM) |
|
|
Ahoj, nikde jinde jsem nedostal odpověď, tak to zkusím ještě tady
Potřebuji sesynchronizovat puštěnou muziku (wav) s grafikou ve hře. Muziku pustím a nelze ji pauznout, nelze seek, ani nic jiného, prostě běží tak jak má, nelze ovlivnit.
Do toho potřebuju sesynchronizovat grafiku zobrazovanou na obrazovce. Třeba pro příklad při každém zvuku bubnu, zobrazit sprite.
Pokud to udělám tak, že nastavím napevno FPS třeba na 60 a jednou za 30FPS zobrazím sprite a sesynchronizuju to tak aby to sedělo, zdálo by se to ok.
Problém nastane, když buď nebude stačit výkon počítače (třeba jen chvilku, aktualizace antiviru...), tak FPS klesne pod 60, takže sprite se rozsynchronizuje s muzikou a bude se objevovat až do konce ve špatném místě. A nebo když buben nebude znít přesně na třicátým FPS, ale třeba na 30,1FPS, tak ke konci písničky se to taky rozjede mimo sebe.
Sice jsem si vytvořil pomůcku, která mi každou sekundu vrací grafiku na správné místo, pro případ že by se to rozjelo, ale je to nanic. Je vidět jak to skoro každou sekundu cukne.
Takže má někdo nějakou radu jakým způsobem tohle zprovoznit bez cukání? Třeba podobné řešení musí mít různé trackery na tvorbu hudebních modulů, tam se dá snadno měnit BPM (rychlost přehrávání) a nezávisí to absolutně na ničem (fps, vytížení procesoru...).
Použití timeru zklamalo, nedokázal spouštět funkci v přesně stejný čas po celou dobu a jiné spolehlivé/přesné řešení mě nenapadá. |
|
Návrat nahoru |
|
|
Mem
Založen: 28. 07. 2007 Příspěvky: 1959 Bydliště: Olomouc
|
Zaslal: 19. únor 2009, 21:51:29 Předmět: |
|
|
No u té trackované hudby ti knihovna nebo rutina co to přehrává umí určitě podat (např. asynchronním eventem) informaci, když skočí na další řádek, mám dojem, že jsem s něčím podobným i pracoval u přehrávání MODů. To co používáš na přehrávání hudby/samplu by mohlo umět něco podobného. Druhá varianta je detekovat BPM čistě z přehrávaného zvuku, pokud je to tvoje hudba a máš tam třeba pravidelný beat, tak to není problém napsat (já psal pro jeden projekt na Guru.com realtime analyzátor vstupního zvuku pro detekci otáček motoru na sněžném skútru )
Jinak poznámku s FPS a jeho výpadkem jsem nepochopil, víš přece, jak rychle ti běží hudba (a ta se nezasekává, ne) a pokud se ti povede provést synchronizaci, tak víš přesný čas a je ti úplně jedno, kdy budeš kreslit další frame. Prostě si spočítáš čas který uplynul od předchozího obrázku a podle toho animuješ. To samé přece musíš mít už implementované i pro normální kreslení, dělá se to úplně běžně, nebo ty skutečně spoléháš na fixní fps? _________________
Naposledy upravil Mem dne 19. únor 2009, 21:54:49, celkově upraveno 1 krát |
|
Návrat nahoru |
|
|
Ladis
Založen: 18. 09. 2007 Příspěvky: 1536 Bydliště: u Prahy
|
Zaslal: 19. únor 2009, 21:54:23 Předmět: |
|
|
Ve spouste audio knihovnach je mozne na zpracovavana audio data hodit callback, ktery muzes pouzit treba k "zobrazeni" hudby. Tak neco takoveho pohledej v tebou pouzivanem API, vzdyt to pouzivaji vsechny prehravace, co umi "vizualizovat" hudbu.
Samozrejme zalezi na formatu audio souboru, pokud je to MP3/WAV, tak musis bubny apod. jen odhadovat podle hlasitosti v ruznych pasmech frekvenci. Kdyby jsi pouzival MIDI nebo nejaky trackerovy format, tak tam jsou primo "noty", ale to by jsi si musel najit nejaky loader, aby jsi moh pracovat s puvodnimi daty namisto vysledneho WAVE vystupu do zvukovky.
Pokud jde jen o synchronizaci, tak bych to resil taky tim callbackem, pac ten prijde presne na dalsi blok dat, a ten blok dat (audio chunk) ma vzdy pevnou casovou delku (v zavislosti na nastaveni kvality prehravani audia zadanem pri inicializaci). _________________ Award-winning game developer |
|
Návrat nahoru |
|
|
rotacak
Založen: 19. 02. 2009 Příspěvky: 28
|
Zaslal: 19. únor 2009, 22:31:13 Předmět: |
|
|
Detekovat to nepůjde, protože nejde jen o bubny ale o ostatní zvuky a nelze se spolehnout na detekci, která by ve složité muzice ani nešla použít. Ale já mám "noty" puštěné současně s muzikou, jde "jen" o to, aby byly puštěné stejnou rychlostí a nerozjížděly se.
Teď to mám udělané podle FPS jako nouzové řešení. Jak říkám, zkoušel jsem timer a ten nebyl schopen udržet volání funkce v daném čaovém intervalu, jestli je to vůbec možné. Protože dejme tomu, že teď mi to jakž takž funguje na 60FPS. To je 60x provedení hlavní smyčky za sekundu. Kdybych to chtěl mít nezávislé na FPS, použil bych ten timer/event aby spustil popojetí "not" na další řádek každých 16,666666666666666666666666666667 milisekund.
A stejně by se to nejspíš rozjelo, nemluvě o tom, že takhle velké číslo mi to ani nedovolí použít a když tam dám 16,6 nebo 16,7, tak na konci písničky jsem zase mimo.
Takže buď použít spolehlivější timer, nebo to udělat jinak? Jde vůbec v takhle malém čase spolehlivě pravidleně volat funkce? Protože pak se taky může stát, že než se dokončí volaná funkce, tak už je volána znovu a pak si nepomůžu.
Ladis: máš nějakej příklad jaká knihovna by na to byla vhodná? Jedná se o wav. Nejradši bych ale měl nějké svoje řešení. |
|
Návrat nahoru |
|
|
franz
Založen: 30. 07. 2007 Příspěvky: 1325
|
Zaslal: 19. únor 2009, 22:33:28 Předmět: |
|
|
Musíš se řídit pozicí v hudbě, kterou taky každý přehrávač vrací (například v fmod je to FSOUND_Stream_GetPosition).
Vytvořil bych si proměnnou 0, která se s každým tickem zvýší o 1 tolikrát, dokud bude její hodnota menší, než pozice v hudbě (a s každým zvýšením otestovat událost - zde bude ručně nadefinováno, na které hodnotě se co stane).
// Samozřejmě samotná grafika musí fungovat stejně, nikoliv fixní fps, ale s každým tickem zahýbat grafikou tolik, kolik ms uteklo od ticku minulého. |
|
Návrat nahoru |
|
|
Marek
Založen: 28. 07. 2007 Příspěvky: 1782 Bydliště: Velká Morava
|
Zaslal: 19. únor 2009, 22:50:29 Předmět: |
|
|
Co myslíš slovem "timer"? Používals doufám performance counter, ne? Protože měřit čas něčím jiným ani nemá smysl. _________________ AMD Open Source Graphics Driver Developer |
|
Návrat nahoru |
|
|
pcmaster
Založen: 28. 07. 2007 Příspěvky: 1824
|
Zaslal: 20. únor 2009, 01:53:19 Předmět: |
|
|
Podla mna ma ovela zakladnejsi problem a timerom mysli nejaku blbu timer komponentu v nejakom IDE (Delphi, C#...)
Rotacak: zabudni, ze timery existuju!
Ty potrebujes mat game loop, ktory je asi nasledovny:
kód: |
while True:
timeNow = getCurrentMilliseconds()
delta = timeNow - lastTime
lastTime = timeNow
..
update game logic
..
render some stuff
|
getCurrentMilliseconds() bude nieco ako timeGetTime() alebo queryPerformanceCounter() ako spominal Eosie. Proste to vrati aktualny cas. Delta je cas, ktory uplynul od predchadzajuceho snimku. Nie je tam nijaky sleep (ale moze byt) a bezi to tak rychlo, ako to len ide. To znamena, ze kazdy frame moze byt (a bude) delta trochu odlisne!
V update/render si vygenerujes svoje "reakcie" na hudbu (ktorej frekvencia je dopredu znama!). Mozes to spravit asi takto:
V pripade, ze timeNow >= timeToGenerate, vygenerujes sprite a "posunies" vzhladom na uplynuly cas.
Napr:
kód: |
position = startPos + velocity * timeFromStart,
kde timeFromStart=timeNow-timeToGenerate
|
V pripade, ze to neplati, nevygenerujes nijake sprity/reakcie. V pripade, ze uplynul cas, za ktory sa malo vygenerovat viac spritov, vygenerujes viac spritov a kazdy patricne nastavis. timeToGenerate si spocitas z frekvencie, napriklad timeToGenerate[i] = startOfTheUniverse + i * (1/freq). Dufam, ze chapes
Tymto sposobom budes mat na obrazovke vzdy tolko spritov, kolko potrebujes a bude jedno aky rychly je pocitac (ci to bezi 85 FPS alebo 30 FPS a hudba ma furt frekvenciu 60 Hz) _________________ Off-topic flame-war addict since the very beginning. Registered since Oct. 2003!
Interproductum fimi omne est. |
|
Návrat nahoru |
|
|
Mem
Založen: 28. 07. 2007 Příspěvky: 1959 Bydliště: Olomouc
|
Zaslal: 20. únor 2009, 08:23:27 Předmět: |
|
|
pcmaster: Díky za rozepsání mé poznámky "Prostě si spočítáš čas který uplynul od předchozího obrázku a podle toho animuješ. To samé přece musíš mít už implementované i pro normální kreslení, dělá se to úplně běžně" _________________
|
|
Návrat nahoru |
|
|
wozembouch
Založen: 03. 09. 2007 Příspěvky: 31
|
Zaslal: 20. únor 2009, 12:06:02 Předmět: |
|
|
rotacak napsal: |
... použil bych ten timer/event aby spustil popojetí "not" na další řádek každých 16,666666666666666666666666666667 milisekund.
A stejně by se to nejspíš rozjelo, nemluvě o tom, že takhle velké číslo mi to ani nedovolí použít a když tam dám 16,6 nebo 16,7, tak na konci písničky jsem zase mimo. |
Ano, protoze s kazdym "uderem" timeru scitas chybu...
Osobne bych pozici v notach pocital v game loopu takhle:
Pozice := (CurrentTimeStamp - StartMusicTimeStamp) / 16.6
StartMusicTimeStamp je casova znacka, kterou si ulozis pri startu hudby. K zjisteni casovych znacek pouzij QueryPerformanceCounter a QueryPerformanceFrequency ... |
|
Návrat nahoru |
|
|
quas4
Založen: 18. 10. 2007 Příspěvky: 199
|
Zaslal: 20. únor 2009, 12:56:01 Předmět: |
|
|
pcmaster napsal: |
Ty potrebujes mat game loop, ktory je asi nasledovny:
kód: |
while True:
timeNow = getCurrentMilliseconds()
delta = timeNow - lastTime
lastTime = timeNow
..
update game logic
..
render some stuff
|
|
Tak tohle presne nedoporucuju. Prudka zmena fps je v tomto podani pro oci citelna. Mam velmi dobre zkusenosti s oddelenim logiky (konstantni frekvence) od renderingu. viz zde: http://gafferongames.com/game-physics/fix-your-timestep/ |
|
Návrat nahoru |
|
|
pcmaster
Založen: 28. 07. 2007 Příspěvky: 1824
|
Zaslal: 20. únor 2009, 14:25:20 Předmět: |
|
|
Ja osobne si myslim, ze je to pre neho velmi vhodne riesenie. Nemusi sa trapit s vlaknami a ich synchronizaciou a tak podobne. A pomoze mu to pochopit, ze timer je zly
Okrem toho, ak rozdelis logiku do viacerych vlaken, tak ti sleep() nikdy nezaruci, ze bude vlakno spat presne tak dlho, ako potrebujes, plus musis este zapocitat cas potrebny na synchronizaciu na zdielanych datach a aj tak si musis nieco podobne vzdy vypocitat.
Netvrdim, ze je to ultimatne najlepsie riesenie, ale pre neho je dobre. _________________ Off-topic flame-war addict since the very beginning. Registered since Oct. 2003!
Interproductum fimi omne est. |
|
Návrat nahoru |
|
|
rotacak
Založen: 19. 02. 2009 Příspěvky: 28
|
Zaslal: 20. únor 2009, 14:35:19 Předmět: |
|
|
Díky za rady, pokusím se tím prohrabat. |
|
Návrat nahoru |
|
|
quas4
Založen: 18. 10. 2007 Příspěvky: 199
|
Zaslal: 20. únor 2009, 19:37:50 Předmět: |
|
|
pcmaster napsal: |
Okrem toho, ak rozdelis logiku do viacerych vlaken, tak ti sleep() nikdy nezaruci, ze bude vlakno spat presne tak dlho, ako potrebujes, plus musis este zapocitat cas potrebny na synchronizaciu na zdielanych datach a aj tak si musis nieco podobne vzdy vypocitat. |
Moment, o vlaknech jsem nic nepsal a ani v clanku o nich neni zadna zminka (nepocitam diskusi). Je to jen elegantni reseni (vlakna nejsou potreba) jak se vyhnout neprijemnym efektum pri rychlych zmenach fps a zaroven mit fixni frekvenci aktualizace logiky. |
|
Návrat nahoru |
|
|
pcmaster
Založen: 28. 07. 2007 Příspěvky: 1824
|
Zaslal: 20. únor 2009, 20:54:26 Předmět: |
|
|
Ja sa musim priznat, ze som ten clanok necital a nespravne som vyvodil, ze odporucas druhy pristup. _________________ Off-topic flame-war addict since the very beginning. Registered since Oct. 2003!
Interproductum fimi omne est. |
|
Návrat nahoru |
|
|
Augi
Založen: 28. 07. 2007 Příspěvky: 782 Bydliště: Čerčany
|
Zaslal: 20. únor 2009, 21:03:49 Předmět: |
|
|
Vlákna taky bylo první, co mě napadlo, ale v tom článku se zjednodušeně řečeno píše jen o tom, že se průběžně sčítají rozdíly času a když ten součet přesáhne určité hodnoty, tak se teprve provede update logiky/fyziky. Příp. se to dá vylepšit o "blendování" předchozího a následujícího stavu.
To je dobrej nápad, kterej jednoduše ošetří případy příliš vysokého FPS. Příliš malé FPS se dá řešit jednoduše rozdělením intervalu a provedení několik aktualizací logiky/fyziky. |
|
Návrat nahoru |
|
|
|