Kirjoittaja: sooda
Kirjoitettu: 11.07.2004 – 11.07.2004
Tagit: ääni, koodi näytille, vinkki
Kiinnostuin WAVin formaatista koska sain uudet kajarit. Aattelin tehdä testausohjelman niille :D
WAVia on montaa eri vormaattia, mutta kivoin on "canonical wave format" eli joku perushomma (http://www.lightlink.com/tjweber/StripWav/Canon.html sain tiedot formaatista).
En jaksa tota headerin formaattia selittää tässä koska kaikki varmaan osaa englantia ainaki sen verran että osaa ton sivun lukea. Tässä käytetään PCM (Pulse Code Modulation) -koodausta. Mulla ei ole mitään tarkkaa hajua miten toi toimii, mutta sain sellaisen käsityksen että se selitetään helpoimmin näin: filussa on joko tavuja tai integerlukuja peräkkäin (siis siellä missä on äänidata). Jokainen näistä antaa ämyrille infon että tunge kartiota n paljon eteenpäin, eli täysi arvo on että kajari on sama kun siihen tungettaisiin tasavirtaa sen verran kuin se kestää. Minimiarvo on sitten sama toisinpäin eli käännetään virtalähteen piuhat toisteppäi :). (Niille jotka ei tiedä: kaiutin toimii siten että siinä on kartio joka liikkuu edestakaisin tuottaen ääntä.) Neliöaallon tapauksessa kahta arvoa heilutellaan edestakaisin tyyliin 255-0-255-0 jolloin kartio pomppii edestakaisin ja syntyy ääntä. Toivottavasti joku osaa selittää paremmin :)
Noh ite vinkissä on kivoja sovellettavia funkkareita jotka tekee neliö- tai siniaaltoa ja soittaa sen. Siniaallosta tein kivan hommelin(SiniAaltoLiuku) jolla saa lineaarisen siniaallon x Hz:stä y:hyn. Neliöaaltoon en jaksanut tehdä kun se kuulostaa niin rumalta :)
Ainiin: noi hommelit jotka vääntää hertsiarvosta sen mikä filuun ängetään on tejeeziltä. Kiitos tejeez. (olisin iteki kyllä googletuksen jälkeen löytänyt mutta tejeez ehti eka.)
Private Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long Private Sub NeliöAalto(Taajuus, Pituus, Voimakkuus) On Error Resume Next 'jos vaikka wav.wav olisi käytössä jo. lenkku = Pituus * 44100 'koko filun pituus, käytetään samplerate 44100:aa. Kill "wav.wav" Open "wav.wav" For Binary As #1 Put #1, , "RIFF" 'RIFF formaattia on waveissa. Put #1, , CLng(28 + lenkku) 'filun pituus - 8 Put #1, , "WAVEfmt " 'wave ja fmt hommeli Put #1, , CLng(16) 'fmt header pituus Put #1, , CInt(1) '1 meinaa että pcm formaatti. Put #1, , CInt(1) 'kanavat, 1 = mono. Stereota ei tässä tarvita Put #1, , CLng(44100) 'samplerate Put #1, , CLng(44100) 'bps Put #1, , CInt(1) 'kertoo yhden samplen pituuden Put #1, , CInt(8) 'bitps Put #1, , "data" 'kertoo että data alkaa tästä Put #1, , CLng(lenkku) 'datan pituus ÄäniPituus = 22050 \ Taajuus 'lasketaan taajuushommeli, tästä kiitokset tejeezille (olisin pienen miettimisen jälkeen varmaan itekin kyllä keksinyt). 'ääni tehdään kahta tavua heiluttelemalla, mitä erilaisemmat sitä isompi volyymi. ÄäniEka = 127 + Voimakkuus / 100 * 128 ÄäniToka = 128 - Voimakkuus / 100 * 128 'tehdään äänet 'neliöaalto on tyyliin: tavu 255, tavu 0, tavu 255, tavu 0, ... tai tavu 255, tavu 255, tavu 0, tavu 0, ... For i = 1 To lenkku ÄäniKohta = ÄäniKohta + 1 If ÄäniKohta > ÄäniPituus Then ÄäniJuttu = 1 - ÄäniJuttu: ÄäniKohta = 0 If ÄäniJuttu Then Put #1, , CByte(ÄäniToka) Else Put #1, , CByte(ÄäniEka) Next Close 'filu sulki sndPlaySound App.Path & "\wav.wav", 1 'soita se End Sub Private Sub SiniAalto(Taajuus, Pituus, Voimakkuus) On Error Resume Next 'jos vaikka wav.wav olisi käytössä jo. lenkku = Pituus * 44100 'koko filun pituus, käytetään samplerate 44100:aa. Kill "wav.wav" Open "wav.wav" For Binary As #1 Put #1, , "RIFF" 'RIFF formaattia on waveissa. Put #1, , CLng(28 + lenkku) 'filun pituus - 8 Put #1, , "WAVEfmt " 'wave ja fmt hommeli Put #1, , CLng(16) 'fmt header pituus Put #1, , CInt(1) '1 meinaa että pcm formaatti. Put #1, , CInt(1) 'kanavat, 1 = mono. Stereota ei tässä tarvita Put #1, , CLng(44100) 'samplerate Put #1, , CLng(44100) 'bps Put #1, , CInt(1) 'kertoo yhden samplen pituuden Put #1, , CInt(8) 'bitps Put #1, , "data" 'kertoo että data alkaa tästä Put #1, , CLng(lenkku) 'datan pituus 'tehdään äänet VolKerroin = Voimakkuus / 100 * 127 'äänenvoimakkuus For i = 1 To lenkku Put #1, , CByte(128 + Sin(Taajuus / 44100 * i * 2 * 3.14159265358979) * VolKerroin) 'tämänkin kaavan tejeez kekkasi ennen mua. Next Close 'filu sulki sndPlaySound App.Path & "\wav.wav", 1 'soita se End Sub Private Sub SiniAaltoLiuku(AlkuTaajuus, LoppuTaajuus, Pituus, Voimakkuus) On Error Resume Next 'jos vaikka wav.wav olisi käytössä jo. lenkku = Pituus * 44100 'koko filun pituus, käytetään samplerate 44100:aa. Kill "wav.wav" Open "wav.wav" For Binary As #1 Put #1, , "RIFF" 'RIFF formaattia on waveissa. Put #1, , CLng(28 + lenkku) 'filun pituus - 8 Put #1, , "WAVEfmt " 'wave ja fmt hommeli Put #1, , CLng(16) 'fmt header pituus Put #1, , CInt(1) '1 meinaa että pcm formaatti. Put #1, , CInt(1) 'kanavat, 1 = mono. Stereota ei tässä tarvita Put #1, , CLng(44100) 'samplerate Put #1, , CLng(44100) 'bps Put #1, , CInt(1) 'kertoo yhden samplen pituuden Put #1, , CInt(8) 'bitps Put #1, , "data" 'kertoo että data alkaa tästä Put #1, , CLng(lenkku) 'datan pituus 'tehdään äänet VolKerroin = Voimakkuus / 100 * 127 'äänenvoimakkuus For i = 1 To lenkku Taajuus = AlkuTaajuus + i / lenkku * (LoppuTaajuus - AlkuTaajuus) 'taajuus alun ja lopun väliltä Put #1, , CByte(128 + Sin(Taajuus / 44100 * i * 2 * 3.14159265358979) * VolKerroin) Next Close 'filu sulki sndPlaySound App.Path & "\wav.wav", 1 'soita se End Sub
Vau, tolla saa aikaan hienoja ääniä. :D Pitääpä joskus itsekin perehtyä tuohon API-funktioon.
Mitään ei tapahdu?
Kivoja ääniä. Voisit ehkä lisätä vielä lisää efektejä?
Sainki toimimaan.
peki: voithan ite tehdä ihan mitä haluat kun nyt näet miten homma toimii.
Yksi asia askarruttaa vielä minua. Miten taajuudet pitää ilmoittaa, jos haluaa saada useamman äänen kuulumaan yhtä aikaa?
Antti: en nyt ihan tainnut tajuta kysymystäsi, mutta miksaus (kahden äänen yhdistäminen) tapahtuu yksinkertaisesti lisäämällä signaalit yhteen. Eli jos sinulla on pulssiaallon senhetkinen näyte (sample) muuttujassa a ja siniaallon näyte muuttujassa b, miksaat nuo yhteen yksinkertaisesti laskemalla c = a + b. Tällöin tunkemalla c-muuttujaa tiedostoon (tai ulos suoraan äänikortille) tulevat molemmat äänet yhtäaikaa.
Tietysti kannattaa huolehtia tarvittavista normalisoinneista, eli tuossa tapauksessa kannatanee jakaa signaali kahdella lisäysoperaation jälkeen ettei signaali klippaa.
Melko hyvältä ja yksinkertaiselta koodilta näyttää. Pistää vaan silmään yksi asia:
For i = 0 To lenkku
Tuo kirjoittaa wav-tiedostoon yhden ylimääräisen tavun! Eipä se tietty kiintolevyä pahemmin rassaa, mutta jos tuota käytetään pohjana tulevissa ohjelmissa niin... :P
lainaus:
Melko hyvältä ja yksinkertaiselta koodilta näyttää. Pistää vaan silmään yksi asia:
For i = 0 To lenkkuTuo kirjoittaa wav-tiedostoon yhden ylimääräisen tavun! Eipä se tietty kiintolevyä pahemmin rassaa, mutta jos tuota käytetään pohjana tulevissa ohjelmissa niin... :P
Kiitti kun huomautit, korjattu =)
loistava! itse jo olen miettinyt jonkin aikaa että mites homma toimii, tai siis sen olen tiennyt miten wavi rakennetaan (esim tekstitiedostossa) mutta enpä ole osannut tehdä tämmöistä lelua joka sitten näpertää kaiken kunnolla :) loistava, ja tuosta klippaamisesta sen verran niin homman voi säätää vaikkapa kanava-sliden sekä pieni yksinkertainen kompressori joka määrittelee että monella jaetaan luku jotta ei klippaisi, siihen voi vaikkapa tunkea maksimi-rajan tyyliin:
if äänenluku > maksimiraja - jotain then käytä kompressoria end iffii ;)
Ei siihen mitään kompressoria kannata kyllä lähteä tunkemaan :)
Oisko exeä?
En tiedä miksi halusit nimenomaan tehdä WAV tiedoston ensin ja soittaa sitte vasta sen. Aika helppoa olisi vain tehdä ääni muistiin ja soittaa se. Sillätavalla olisi helppoa sitten tehdä mixsaushohjelma jolla säädetään korkekuskia ym.. useampia ääniä yhteen jne.