lazarus i bass.dll - rysowanie wykresu waveform

0

Witam.

Napisałem w Lazarusie w oparciu o bass.dll prosty odtwarzacz plików wav.
W trakcie odgrywania plików odtwarzacz realizuje bieżące wizualizacje FFT lub waveform.
Wszystko działa tak jak trzeba ale ...
teraz chciałbym dodatkowo po "otwarciu" wav

channel := BASS_StreamCreateFile(False, filename, 0, 0, 0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});

narysować jego kompletny wykres waveform.

Próbuję, w pętli for, pobierać z wav paczki danych korzystając z funkcji

BASS_ChannelSetPosition(channel, pozycja, BASS_POS_BYTE);
BASS_ChannelGetData(channel, @WaveData, 2048);

i niestety w zmiennej WaveData ciągle mam te same stałe ale "przypadkowe" wartości.

Natomiast jeśli dam

BASS_ChannelPlay(channel, true);

i "ręcznie" pobieram z wav bieżące dane przez

BASS_ChannelGetData(channel, @WaveData, 2048);

to wszystko mi działa ok.

Wydumałem więc, że bass.dll nie udostępnia tych danych jeśli wav nie jest odgrywany.
Czyżby tak było ?
czy też źle się do tego zabrałem.

Proszę o wskazówki i wyrozumiałość,
jestem programistą amatorem :)

dodanie znaczników <code class="delphi"> - fp

0

Nigdy tak z bassem nie musiałem kombinować. Ale jeśli nie ma przykładu w examples na rysowanie waveform. Ponieważ na inne bajery jak wykresy przy odtwarzaniu od dawna był przykład w WinAPI. To ja bym pokombinował raczej tak jak wedlug opisu na: http://www.un4seen.com/doc/#bass/BASS_ChannelGetData.html - bo Ty przekazujesz rozmiar luzem podają jakąś wielkość. A tutaj raczej trzeba operować na wymienionych na powyższej stronie stałych. Z których jak widzę z pliku nagłówkowego do bass, żadna nie ma wartości 2048 raczej. Być może stąd te przypadkowe dane.

Nie widzę też żadnego wspomnienia, że można pobierać te dane tylko przy odtwarzaniu. Jeżeli uzyskane Handle jest prawidłowe to myślę, że to powinno się udac. Jednak, w bass.dll nie jestem ekspertem i nigdy nie pisałem z użyciem tej dllki aż tak zaawasnowanych rzeczy, bo zwykle interesowało mnie tylko odtworzenie plików, ewentualnie ładowanie bass.dll z zasobów exeka, a ostatnio proste wyświetlenie danych o module muzycznym. Także ktoś może coś jeszcze Tobie lepszego i konkretniejszego tutaj doradzi.

EDIT: a nie przepraszam, jednak można podać konkretną ilośc bajtów. Teraz doczytałem. Ale spróbuj jeszcze ze stałymi może. Ja póki co nic lepszego nie wymyślę.

0

Witam ponownie.

Oczywiście okazało się, że da się pobrać te dane.
Otworzyłem dodatkowo plik tylko do pobrania danych

chanwav := BASS_StreamCreateFile(False, f, 0, 0, BASS_STREAM_DECODE {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});

Istotna jest flaga BASS_STREAM_DECODE.

Potem już funkcje pozycjonowania i pobierania

BASS_ChannelSetPosition(chanwav, pozycja, BASS_POS_BYTE);
BASS_ChannelGetData(chanwav, @WaveData, 2048);

działają tak jak należy.

Teraz mam kolejne pytanie,
jak uśrednić dane z kilku/kilkudziesięciu tysięcy pobranych bajtów przypadające na 1 piksel wykresu (oś X) aby wyglądało to tak jak na wykresach waveform ?
Próbowałem wyliczać średnią, wyznaczać maksimum, ale efekt jest marny :(
Jakaś funkcja matematyczna ?

0

Niestety nie umiem Ci pomóc w tym. Z matmy byłem, jestem i zawsze będę totalny lama/noga/baran. Już się z tym pogodziłem. Jedyne co mogę doradzić to przeanalizowanie sobie przykładów w podkatalogach SampleVis oraz spectrum w paczce z bass.dll, dokumentacją i przykładami w kilku językach.

1

jak uśrednić dane z kilku/kilkudziesięciu tysięcy pobranych bajtów przypadające na 1 piksel wykresu (oś X) aby wyglądało to tak jak na wykresach waveform ?
Weź wartość maksymalną i minimalną z danego odcinka, i narysuj krechę pionową od min do max.
Pamiętaj, że sample są ze znakiem, więc zero masz po środku.

0

Lub obliczaj na zmianę min i max i rysuj co krok krechę od poprzedniej do nowej wartości.

0

Znalazłem dwie metody kalkulacji, może się to komuś przyda.

Pierwsza RMS.

float RMS = 0;
for (int a = 0; a < BlockSize; a++)
{
   RMS += samples[a] * samples[s]; 
}
RMS = sqrt(RMS / BlockSize);

Druga Min/Max.

float Max = - 1000000;
float Min = 1000000;
for (int a = 0; a < BlockSize; a++)
{
   if (samples[a] > Max) Max = samples[a];
   if (samples[a] < Min) Min = samples[a];
}

Pierwszą już wypróbowałem, efekt jest taki sobie.
Zabieram się za drugą :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1