artykuły

Delphi - Nagrywanie dźwięku

15:49
pon, 21 styczeń 2008
Artykuł pokazuje w jaki sposób niskopoziomowo (tzn. nie przez MediaPlayer ;) ) nagrywać dźwięk w taki sposób by mieć kontrole na danymi w czasie rzeczywistym.
Ten artykuł nie jest jeszcze dopracowany. Póki co przedstawia on sposób w jaki można nagrywać dźwięk poprzez niezbyt dopracowany moduł pakietu DelphiX, z którym sam miałem problemy. W przyszłości postaram się dodać do tekstu wskazówki, jak używać znacznie bardziej rozbudowanej biblioteki "Bass".

Wstęp

W początkach swojego istnienia, komputery były nieme i głuche. Potem dano im głos, by mogły powiedzieć nam o ewentualnych błędach. Od momentu pojawienia się kart dźwiękowych, komputer stał się multimedialnym sprzętem, który potrafi nie tylko słuchać, ale i śpiewać ;) Jednak żadna maszyna cyfrowa nie zadziała bez odpowiedniego oprogramowania. Zadaniem programisty jest nauczyć komputer słuchać i śpiewać na rozkaz użytkownika.
Z tej racji, że nauka śpiewania jest prosta - pominiemy ją. Trudniej jest nauczyć maszynę słychać, czyli nagrywać dźwięki.
Delphi udostępnia nam możliwość nagrywania dźwięku poprzez standardowy komponent TMediaPlayer. Jest to proste i niezbyt wygodne rozwiązanie. Chcielibyście mieć większą kontrolę nad nagrywanym plikiem? W tym artykule opiszę ogólną zasadę funkcjonowania większości programów do nagrywania dźwięku. Skorzystamy przy tym z bibliotek o nazwie DelphiX (można je było znaleźć na płytkach Eksperta, jest też ogólnie dostępna w Internecie). Zapraszam do lektury.

Ogólna koncepcja nagrywania dźwięku

Ogólnie tak to jest wszystko zaprojektowane, że karta dźwiękowa nagrywa dźwięk do małego buforka. W buforku tym mieści się bardzo niewiele dźwięku. Dlatego aby nagrać dłuższy kawałek (parosekundowy lub parominutowy) należy dane z buforka co chwilę kopiować do pliku.

  1. Uruchomcie Delphi'ego (na marginesie: spotkałem się z komentarzami, że Delphi nie jest chłopczykiem, więc się go nie odmienia ;P )
  2. Przejdźcie doEdytora Kodu(F12) i do listyusesznajdującej się na samym początku modułu dodajcie słówka:  DXSounds, MMSystem, Wave
  3. Przejdź do sekcji public klasy TForm1 i dodaj tam taką procedurę:  procedure ZapiszDoStrumienia(Sender: TObject);
  4. Przejdźcie do sekcjivar(globalne) i dopiszcie takie deklaracje:
    CapturedAudio : TSoundCaptureStream; WaveStream : TWaveStream;
  5. Za słówkiemimplementationdopisz treść proceduryZapiszDoStrumienia(Sender: TObject); procedure TForm1.ZapiszDoStrumienia(Sender: TObject); begin   WaveStream.CopyFrom(CapturedAudio,CapturedAudio.FilledSize);   Application.ProcessMessages; end; W pierwszej linijce następuje skopiowanie zawartości buforkaCapturedAudiodo dużego buforaWaveStream, który bezpośrednio zapisuje dane do pliku.
    Druga linijka jest pusta ku zwiększeniu przejrzystości kodu ;)
    Trzecia linijka gwarantuje nam, że program, w momencie, gdy będzie coś nagrywane, nie będzie dawał oznak "zawieszonego". Tak naprawdę procedura ta wymusza przerwę, aby nasza aplikacja mogła spokojnie przetworzyć napływające do niej komunikaty, np. komunikat odmalowania okna.
  6. Przejdź do widoku formularza (F12). Na formie umieść dwa komponenty typuButton(dwa przyciski) (znajdują się one na palecieStandard). Kliknij na przyciskButton1i wInspektorze Obiektówodszukaj właściwośćCaption, którą zmień na"Rozpocznij nagrywanie". Kliknij teraz na przyciskButton2, przejdź do Inspektora Obiektów, odszukaj właściwośćCaptioni zmień ją na"Zakończ nagrywanie".
  7. Kliknij dwukrotnie na przycisku"Rozpocznij nagrywanie"(Button1). Pojawi się edytor kodu z nowo wygenerowaną procedurką. Uzupełniamy ją następująco:
    CapturedAudio := TSoundCaptureStream.Create(nil); WaveStream := TWaveFileStream.Create('C:\nagrane.wav', fmCreate); CapturedAudio.OnFilledBuffer := ZapiszDoStrumienia; WaveStream.SetPCMFormat(11025,8,1); WaveStream.Open(True); CapturedAudio.Start; Pierwsza linia kodu tworzy nam specyficzny strumień przechwytywania audio. Można powiedzieć, że jest to swego rodzaju bufor, który przechowuje malutką porcję dźwięku i czeka aż ten dźwięk od niego zabierzemy (skopiujemy).
    Druga linia kodu to stworzenie również specyficznego strumieniaTWaveFileStream. Do niego będziemy kopiować poszczególne "porcję" dźwięków z bufora (CapturedAudio).
    Trzecia linijka... jest nieco trudniejsza, gdyż tu wielu nowicjuszów może mieć problemy. Postaram się jednak wszystko wyjaśnić. Pamiętacie jak zadeklarowaliśmy własną procedurkę o nazwieZapiszDoStrumienia??? Chyba pamiętacie. Procedurka ta kopiowała dane z bufora, do naszego strumieniaWaveStream, czyli do pliku 'C:\nagrane.wav'. Otóż w tej linijce następuje tzw. przypisanie procedury obsługującej zdarzenie. Oznacza to, że jakby wskazujemy temu maleńkiemu buforowi (CapturedAudio), którą procedurę ma wywołać, aby skopiowano z niego dane do pliku, w momencie gdy będzie już pełny. Tak więc nasza proceduraZapiszDoStrumieniajest wywoływana gdy buforekCapturedAudiojest pełny i ma ona za zadanie dołączyć dane z tego buforka do dużego buforaWaveStream, który bezpośrednio zapisuje je do pliku 'C:\nagrane.wav'.
    Czwarta linijka ustawia nam format w jakim będą zapisywane dane. Pierwszy parametr mówi o częstotliwości próbkowania, drugi oznacza rozdzielczość (w bitach), trzeci definiuje ilość kanałów (i tutaj 1 kanał - dla dźwięku mono lub 2 kanały - dla dźwięku stereo).
    Piąta linijka jest bardzo ważna. Gdybyśmy o niej zapomnieli (co przychodzi bardzo łatwo), po uruchomieniu nagrywania ujrzelibyśmy błąd. Pewnie zastanawiacie się do czego służy? Otóż otwiera ona strumień. Parametr w nawiasie oznacza czy będzie to otwarcie do zapisu (True), czy też do odczytu (False).
    Piąta linijka rozpoczyna nagrywanie.
  8. Przejdź do widoku formularza (F12) i kliknij dwukrotnie na znajdujący się tam przycisk "Zakończ nagrywanie" (Button2). Pojawi się edytor kodu z nowo wygenerowaną procedurą ;p... Uzupełniamy jej treść następująco: CapturedAudio.Stop; CapturedAudio.Free; WaveStream.Free; Pierwsza linijka zatrzymuje nagrywanie
    Druga linijka zwalnia pamięć strumienia CapturedAudio (buforka).
    Trzecia linijka zwalnia pamięć strumienia WaveStream (bufora).
  9. Nasz program jest gotowy do działania!

Zakończenie

Mam nadzieję, że było to dla Was pożytecznie zmarnowane 20 minut ;) Jak zawsze do artykułu dołączam źródło pisanego w artykule programu. A jeśli chcielibyście nagrywać dźwięk prościej, możecie to zrobić poprzez komponentMediaPlayer(zakładkaSystem). Jednak przy tym rozwiązaniu nie macie praktycznie możliwości wpływania na przebieg tego procesu. Między innymi dlatego szczególnie polecam sposób opisany w artykule.

12345
Delphi - Nagrywanie dźwięku Autor opinii: Czytelnicy, data przesłania: 0

Podobne artykuly:

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    • Bakuś
    • pią, 1 czerwiec 2012, 9:25
    • Nie wiem dlaczego ale u mnie nagrywany dźwięk jest przyspieszony... zmiana częstotliwości próbkowania tylko pogarsza sprawę.
    • Kacpir
    • śro, 19 listopad 2008, 18:08
    • Coś mi to nie działa. Sypie się przy
      Uses Wave
      Nie mógł znaleźć (choć mam XDelphi), to zmieniłem na
      Uses DXWave
      Zadziałało, program się odpalił jednak nie działa jak powinien. Po kliknięciu na "Rozpocznij nagrywanie" program zwiesz się. Owszem, tworzy się plik "nagranie.wav" jednak niczym nie jestem wstanie go odtworzyć. Pozdrawiam, prosiłbym o odpowiedź na e-mail.
Dexter