Elektroda.pl
Elektroda.pl
X
PCBwayPCBway
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Mały odtwarzacz MP3,AAC,MP4 na AT91SAM7S256

Tytus Kosiarski 26 Lis 2011 19:14 37498 51
  • #31
    Tytus Kosiarski
    Poziom 15  
    Acha, poprawność działania programu odtwarzania MP-czwórek sprawdziłem na kilkunastu plikach MP4 i M4A, które pościągałem z Sieci. Niemniej jednak, może się trafić jakiś taki plik, który nie będzie odtwarzany i może powodować np. zawieszenie się odtwarzacza. Proszę wtedy o przesłanie na priv tego pliku lub podanie linka do niego, abym mógł usunąć błędy w programie, uniemożliwiające odtworzenie tego pliku.
    Pozdrawiam, KT
  • PCBwayPCBway
  • #32
    Safrane70
    Poziom 2  
    Świetny projekt, ja od jakiegoś czasu własnie myślę żeby zrobić taki odtwarzacz MP3 do samochodu (i nie tylko) - Jaka byłaby orientacyjna cena złożenia tego projektu (procesor (najlepiej już zaprogramowany), płytka, gniazda, części?? Po "piętach" depcze YAMPP 7 - KIT kosztuje 230 zł. (pod warunkiem że jest jeszcze dostępny).
    Dla mnie w obecnej chwili (praca, dzieci) odpada zbyt długie "chodzenie" przy projekcie i zmuszony jestem do pójścia na łatwiznę - niestety - chroniczny brak czasu... Czy Kolega Tytus ze swojego projektu myśli zrobić KIT do samodzielnego montażu?? Umiejętność operowania lutownicą jeszcze mi pozostała... ;)
  • #33
    Tytus Kosiarski
    Poziom 15  
    Witam:) Dzięki:) Dokumentacja odtwarzacza i dokładniejszy kosztorys jest w moim poście otwierającym ten wątek, całość wynosi tak ok 340zł. Nie przewiduję robienia z tego kitu w celach zarobkowych z dwóch powodów: 1. nie wiem,jak by było z prawami autorskimi, ale wydaje mi się, że kodu dekodera MP3 i AAC nie można wykorzystywać w celach komercyjnych;
    2. nie mam możliwości zaprogramowania procesora poza układem. Jedynie w zmontowanym układzie odtwarzacza. Mogę doradzić jedynie poskładanie we własnym zakresie tego odtwarzacza (z wykorzystaniem dokumentacji) i dogadanie się ze mną na priv w celu zaprogramowania i uruchomienia całości.
    Obecnie testuję poprawność odtwarzania plików MP4 (walka ze zwisami w wyjątkach Data Abort podczas odtwarzania tych plików). Wydaję mi się, że już odtwarzanie przebiega poprawnie, jak już będę pewien poprawności działania, wystawię, oczywiście, kod. Mogę również napomknąć, że pomału przygotowuję się do implementacji kodu tego odtwarzacza na procesorze ATSAM3S4B (pinowo zgodny z SAM7S, ale rdzeń procesora to Cortex M3). Ale to jeszcze zajmie mi czasu... (również chroniczny brak, niestety)
    Pozdrawiam, KT
  • PCBwayPCBway
  • #34
    Safrane70
    Poziom 2  
    Ech te "prawa autorskie" :( Napisałem maila do tej firmy która oferuje YAMPPa (softcom.gda.pl) ale nie dostałem odpowiedzi - pewnie już zarzucili ten projekt. No to nie pozostaje mi nic innego jak po szaleństwach "nocy sylwestrowej" ;) zabrać się za Kolegi projekt :) Poczekam tylko na efekty działań na nowym procesorze :)

    Życzę Wszystkiego Dobrego na Nowy Rok oraz wszelkiej pomyślności :)

    Pozdrawiam również :)
  • #35
    Tytus Kosiarski
    Poziom 15  
    Witam
    OK, po ponad dwumiesięcznej, intensywnej eksploatacji mp-czwórki wyszły na jaw błędy w programie, które kończyły się wyjątkiem Data Abort i "zwisem". Jedną z przyczyn udało się dość łatwo namierzyć, mianowicie wyjątek ten powodowany był tylko podczas odtwarzania jednego, specyficznego pliku MP4. Okazało się, że w tym pliku atom "stsc" składał się tylko z jednego 12-bajtowego wpisu, w którym to wpisie były: 4 bajty indeksu kawałka audio, 4 bajty ilości próbek audio w tym kawałku (ta próbka audio to jest pojedyncza, "surowa" ramka AAC, bez nagłówka ADTS) oraz 4 bajty Sample Duration Index (czas trwania pojedynczej próbki(?); zawsze równy 1). Te ostatnie 4 bajty SDI nie są mi potrzebne i nie wykorzystuję ich. W tym konkretnym pliku we wpisie atomu "stsc" indeks kawałka audio miał wartość 1, natomiast ilość próbek audio w tym kawałku danych była różna od 1 (a nie równa 1, jak w innych plikach z podobnie zbudowanym atomem "stsc"). Po "obczajeniu" tej różnicy w budowie atomu "stsc" wystarczyło wstawić po dwukropku:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    zamiast wartości 1 w pętli odtwarzającej plik MP4 w funkcji play_mp4_file w pliku play_files.c. Ta zmiana spowodowała poprawne już odtwarzanie tego konkretnego pliku MP4.

    Z inną przyczyną wyjątku Data Abort nie było już tak prosto - zawieszanie się w przypadkowych momentach, przy odtwarzaniu różnych plików. Było czasami tak, że cały katalog z plikami MP4 był poprawnie odtworzony do końca, po czym podczas próby ponownego odtworzenia zawartości tego katalogu zwis następował już na pierwszym pliku. Próby manewrowania rozmiarami heap'u i stack'a nie dawały jakiejś widocznej zmiany, nie mówiąc o poprawie. Wielogodzinne odtwarzanie tych plików w trybie debug-u ujawniło w końcu, że problem występuje podczas wykonywania się jednej funkcji RefillBitstreamCache w pliku aac_bitstream.c oraz drugiej funkcji DecodeSectionData w pliku noiseless.c. Wiele czasu zajęło mi ustalenie, co mogło być przyczyną takich problemów. Na właściwy trop naprowadziła mnie obserwacja wartości zmiennej
    bsi->cachedBits w funkcji GetBits w pliku aac_bitstream.c podczas debug-u. Normalnie wartość ta powinna być >=0, gdy jest mniejsza, to w tej funkcji wywoływana jest kolejna funkcja RefillBitstreamCache. Podczas normalnego, prawidłowego dekodowania wartość zmiennej bsi->cachedBits nie była mniejsza niż (-16). Natomiast przed momentem zwisu wartość ta była, owszem, ujemna, ale przyjmowała "kosmiczne" wielkości!!! Wtedy kapnąłem się, że przyczyną takiego zachowania mogą być błędy w odczycie danych odtwarzanego pliku z karty SD (przekłamywanie bajtów). Błędy odczytu niekiedy zdarzały się na tyle rzadko, że możliwe było odtworzenie całego, kilkugodzinnego podkatalogu z plikami MP4 bez zwisów. Zastanawiając się, co by z tym zrobić, pomyślałem, że warto by było wykorzystać sumę kontrolną CRC generowaną przez kartę SD do wyeliminowania błędów odczytu. Dwubajtowa suma kontrolna CRC jest doklejana na końcu każdego 512-bajtowego sektora danych podczas odczytywania karty SD. Wartości CRC wpisuję do tablicy wskazywanej przez wskaźnik SD_CRC_table jak w poniższym kodzie (funkcja sd_get_response_and_read_write_data w pliku SD_Card_functions.c):

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Następnie zapamiętane kody CRC wykorzystuję do porównania z obliczonymi kodami CRC i stosownie do wyniku porównania, ponownego odczytania uprzednio błędnie odczytanych danych, jak w poniższym kodzie (funkcje read_sector i read_multiple_sectors w pliku SD_Card_functions.c):

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Na razie działa:) Wykorzystałem sposób obliczania CRC CCITT z tej strony: http://groups.google.com/group/pl.comp.lang.d...i/browse_thread/thread/ef7c8fcf5605b9eb?fwc=1
    oraz tablicę wielomianu CCITT stąd: https://www.elektroda.pl/rtvforum/topic1350530.html
    Ponadto zmniejszyłem wykorzystanie RAMU do 48kB poprzez usunięcie trzech wielkich tablic ze zmiennych globalnych i dynamiczne tworzenie tych tablic jedynie przed rozpoczęciem odtwarzania pliku MP3, AAC i MP4 oraz usuwaniem tych tablic po zakończeniu odtwarzania tych plików, gdyż przymierzam się powoli do implementacji tego odtwarzacza na procesorze SAM3S4B.
    Pozdrawiam, KT
  • #36
    Tytus Kosiarski
    Poziom 15  
    Witam ponownie

    Dorobiłem jeszcze w programie odtwarzacza jeszcze trochę usprawnień ułatwiających korzystanie z niego (na dotychczasowy mikrokontroler).

    Jednym z nich jest przyspieszenie przewijania w poziomie długich nazw plików i podkatalogów nie mieszczących się w całości na LCD podczas wyświetlania listy tychże. Dotychczas były przewijane one w tempie 1znak / 500ms, teraz jest 1znak/200ms. Uzyskałem to poprzez zwiększenie częstotliwości wywoływania przerwania z timera TC0 poprzez skrócenie jego modulo.

    Następnym usprawnieniem jest usunięcie zwisu odtwarzacza podczas wykonywania się pętli liczącej ilość cyfr składających się na wyświetlany numer wpisu pliku przed jego nazwą. Sporadycznie zdarzało się, że pamięć RAM przechowująca wpisy plików i katalogów obecnych na karcie SD była wypełniana śmieciami. Skutkowało to utknięciem programu w tejże pętli. Wizualnie przedstawiało się to w taki sposób, że czyszczony był wyświetlacz, jego podświetlenie było rozjaśnione ma max i odtwarzacz nie reagował na przyciski. Pomagał wtedy reset. Po przeróbce tej pętli, jak w poniższym kodzie (funkcja main w pliku main.c):



    Kod: c
    Zaloguj się, aby zobaczyć kod

    Na razie działa :)

    Kolejnym usprawnieniem jest ustawienie głośności w połowie zakresu po włączeniu odtwarzacza. Poprzednio ta głośność była nastawiana na max. Skutkowało to niekiedy bólem uszu tuż po włączeniu odtwarzania pliku, zanim user nie nastawił sobie pożądanej głośności. Uzyskałem to poprzez wpis odpowiedniej wartości do przetwornika DAC podczas jego konfigurowania po włączeniu odtwarzacza.

    Ponadto usunąłem jeszcze dwa błędy, których obecność ujawniła się podczas próby odtworzenia jakiegoś nowego pliku MP4 ściągniętego z Sieci. Pierwszy z tych błędów spowodował zwis po odtworzeniu początkowych kilkudziesięciu sekund pliku. Przyczyną okazało się brak sprawdzenia, czy obliczony następny sektor karty przechowujący dane atomu stsz jeszcze mieści się w bieżącym klastrze. Teraz to sprawdzenie odbywa się po obliczeniu wartości zmiennej next_sector_stsz. Ilustruje to poniższy kod (funkcja play_mp4_file w pliku play_files.c):



    Kod: c
    Zaloguj się, aby zobaczyć kod


    Po usunięciu pierwszego błędu okazało się, że ten plik nie był odtwarzany do końca. Całkowity czas trwania pliku był 42min, a koniec jego odtwarzania był po ok. 36min. To był ten drugi błąd. Okazało się, że przyczyną jest nieprawidłowy typ zmiennej liczącej elementy atomu stco. Ten konkretny plik miał więcej jak 65535 elementów atomu stco, a zmienna licząca te elementy była zadeklarowana jako 16-bit. Po zmianie typu tej zmiennej plik był już odtwarzany do końca.

    Pozdrawiam, KT
  • #37
    Tytus Kosiarski
    Poziom 15  
    Witam ponownie :)

    Na początek krótki raport z próby przeportowania softu odtwarzacza na procesor ATSAM3S4B. Niestety, próba nie do końca udana - udało mi się uruchomić jako tako dekodowanie MP3, reszty nie. Główną przyczyną niepowodzenia była wadliwa współpraca portu JTAG tego procesora ze środowiskiem Rowley Crossworks poprzez Macraigor Wiggler. Mianowicie, podczas debugowania, często następowało zrywanie połączenia z komunitatami "Memory read / write time out". Również próba odpalenia programu w trybie Run podczas debugu kończyła się zrywaniem połączenia. Bardzo niekorzystnie prezentowało się to w porównaniu chociażby z Motylkiem, czy później z płytką STM32F4-Discovery. Dlatego zarzuciłem dalsze prace nad tym procesorem.

    Zainteresowałem się natomiast płytką STM32F4-Discovery i jako wprawkę przed poważniejszym wykorzystaniem tego procesora chciałbym zaprezentować dekoder WMA uruchomiony na tej płytce. Dekoder ten dekoduje strumień audio z pliku WMA umieszczonego w pamięci Flash mikrokontrolera. Do dekodowania wykorzystałem stałoprzecinkowy dekoder WMA oparty na projekcie FFmpeg, którą pobrałem stąd: http://www.rockbox.org/tracker/task/4984
    Jako projekt referencyjny, potrzebny do usunięcia błędów, dopisania ekstrakcji danych z formatu ASF niezbędnych do dekodowania i uruchomienia powyższego dekodera wykorzystałem zmiennoprzecinkowy dekoder WMA pobrany stąd: http://en.pudn.com/downloads138/sourcecode/multimedia/audio/detail594413_en.html

    Cała trudność polegała na tym, żeby upchnąć ten dekoder w pamięci mikrokontrolera, gdyż stałoprzecinkowy dekoder był pisany chyba na PC-ta (zmiennoprzecinkowy zresztą też, takie wrażenie odnosiłem). Udało się i obecne zapotrzebowanie na RAM wynosi ok. 125kB (z ponad 256kB oryginalnie). Teraz dekoder dekoduje strumień WMA 22kHz i 44,1kHz, inne fsample jeszcze trzeba dopracować.
    Po zaprogramowaniu mikrokontrolera na płytce STM32F4-Discovery, ten powinien od razu odtwarzać w kółko WMA zawarty we Flash (będzie to piosenka "Czterdzieści lat minęło", bo dziś mam 40 na liczniku :D ) i powinna świecić ciągle zielona LED na tej płytce. Jej mruganie świadczy o nieciągłym dostarczaniu strumienia audio do DAC CS43L22 (procesor wtedy nie wyrabia się). W dołączonym kodzie źródłowym można poeksperymentować.
    Aby dekoder ruszył, trzeba przydzielić 125kB heap oraz 1,5kB stack. Zegar systemowy mikrokontrolera wynosi 52,5MHz, wykorzystany jest HSE z kwarcem 8MHz na tej płytce. Kompilowałem z opcją -O2.

    W paczce są 3 dema WMA (wspomniany czterdziestolatek 44,1kHz; i dwa dema z Winampa, pierwszy 22kHz, drugi 44,1kHz). Program napisałem w IDE Rowley Crossworks ver.2.0.11.

    Jeszcze dorobiłem do tej płytki port JTAG według strony:
    http://searchingforbit.blogspot.com/2012/03/stm32f4discovery-eval-board-with.html
    Działa wyśmienicie z Macraigor Wiggler i dodatkowo jest szybszy (ok. 19kB/s vs 2,4kB/s ST-Link).

    Pozdrawiam, KT
  • #38
    Tytus Kosiarski
    Poziom 15  
    Witam ponownie

    Wprowadziłem poprawki do dekodera WMA, które pozwoliły na odtwarzanie plików CBR oraz VBR z fsample od 8kHz do 48kHz i bitrate od 8kb/s do 320kb/s. Ponadto wprowadziłem odczyt strumienia WMA z 1kB bufora RAM uzupełnianego na bieżąco danymi odczytywanymi z pliku WMA zapisanego we Flash (poprzednio był odczyt danych wprost z pamięci Flash) w ramach przygotowania do późniejszego odczytu strumienia WMA np. z karty SD. Niestety, dekoder ten (jak na razie) uniemożliwia odtwarzanie plików WMA Lossless. Przyczyną tego jest zwrot wartości NULL przez funkcję avcodec_find_decoder(wma->codec_id) w pliku main.c, gdyż jej argumentem jest wtedy wma->codec_id == CODEC_ID_NONE i póki co, nie wiem, co z tym dalej zrobić... Może ktoś będzie mieć jakiś pomysł :) Dla pozostałych WMA argumentem tej funkcji jest wma->codec_id == CODEC_ID_WMAV2 i dekoder pracuje normalnie.

    Do projektu dekodera dołączam paczkę z kilkoma przykładowymi strumieniami WMA w plikach *.c. Trzeba dołączyć do projektu jeden z tych plików, odkomentować odpowiednią linię w pliku demo.h, skompilować i wgrać do mikrokontrolera. Wówczas ten będzie w kółko odtwarzał materiał dźwiękowy z tego strumienia WMA (teraz demo z Winamp-a).

    Acha, w poprzednim opisie nie dodałem, oprócz 125kB heap i 1,5kB stack dekoder wykorzystuje też 64kB pamięć TCM Data RAM w tym mikrokontrolerze (STM32F407 na płytce Discovery).

    Pozdrawiam, KT
  • #39
    mrh
    Poziom 18  
    Mam pytanie... wiesz może jak zrobić odtwarzanie plików mp3 z VBR ?
    Bo jak odtwarzam pliki z 320kb/s to słychać że jest troszkę wolniej niż np. z komputera.
  • #40
    Tytus Kosiarski
    Poziom 15  
    Witam
    Powiedz mi, jakie jest fsample tych plików. Bo VBR nie ma tu nic do rzeczy. Domyślam się, że może chodzić o pliki z fsample 48kHz. Ostatnia wersja odtwarzacza MP3 na AT91SAM7S256 przewiduje, że pliki 48kHz są odtwarzane przy zegarze mikrokontrolera ok.67,7MHz, a powinny być odtwarzane przy tym zegarze równym ok. 73,7MHz (funkcja select_clock w pliku play_files.c)
    Osobiście nie porównywałem odtwarzania takich plików na kompie i odtwarzaczu, toteż wydawało mi się, że to spowolnienie odtwarzania nie będzie aż tak mocno słyszalne, a chciałem zmniejszyć pobór prądu z akumulatora. Aby przekonać się, że to o to chodzi, proponuję (dla przypadku case 48000: case 24000:) odkomentować w tej funkcji wszystko, co dotyczy zegara 73,7MHz po słowie kluczowym default; zakomentować wszystko, co dotyczy zegara 67,7MHz, skompilować i wgrać do mikrokontrolera. Tempo odtwarzania powinno być OK.
    Pozdrawiam, KT
  • #41
    mrh
    Poziom 18  
    Mam np. plik mp3 44100Hz i 128kb/s działa normalnie, ale gdy mam plik 44100Hz i 320kb/s to już słuchać że troszkę jest opóźnione. Nie wiem właśnie co mam nie tak.
  • #42
    Tytus Kosiarski
    Poziom 15  
    Przed chwilą sprawdziłem, na Winampie i na moim odtwarzaczu, plik 320kb/s (co prawda CBR) i 44,1kHz i ja nie słyszę żadnej różnicy w prędkości odtwarzania (albo ja mam dębowe ucho...). Zobacz, proszę, poprzez jednoczesne wciśnięcie obydwu przycisków regulacji głośności w górę i w dół, podczas odtwarzania tego pliku, jaka jest fclk mikrokontrolera.
  • #43
    mrh
    Poziom 18  
    Tylko że ja robię odtwarzacz mp3 na płytce STM32F4-Discovery i pliki są czytane z pendrajwa. Wydaje mi się ze mój kod nie jest zbyt optymalny i dlatego mi zamula.
  • #44
    Tytus Kosiarski
    Poziom 15  
    A to co innego. Na razie jeszcze nie doszedłem do tego. Póki co, na STM32F4 uruchomiłem WMA z Flasha i teraz rozpracowuję TFT 320x240. Spróbuj pomanewrować argumentami w funkcji
    Kod: c
    Zaloguj się, aby zobaczyć kod
    gdzie ciało funkcji config_I2S jest w pliku spi2_i2s.c (w paczce ze źródłem). Oczywiście, wma->sample_rate i wma->channels należy zastąpić odpowiednimi wartościami pobranymi z nagłówka ramki MP3.

    Acha, zmiana tych wartości powoduje zmianę tempa odtwarzania pliku, można na pałę wpisywać cokolwiek i odsłuchać, jaki to daje efekt.
  • #45
    mrh
    Poziom 18  
    Coś tam poprawiłem i jest lepiej. Teraz jak odtwarzam mp3 320kb/s to słychać tak jakby procesor nie wyrabiał z dekodowanie mp3. Jak pobierałem dane z karty SD to 320kb/s działało bez problemu. Może wrzuciłbym niektóre ważniejsze funkcje do pamięci RAM to może szybciej będą się wykonywać i będzie działać jak należy.
  • #46
    Tytus Kosiarski
    Poziom 15  
    Może za długo trwa odczyt danych z pendrive? Skoro piszesz, że odczyt z karty SD był OK. Wrzucanie funkcji do RAMu nie wydaje się konieczne, jak niekonieczne było to na ARM7TDMI (wolniejszym). Może trzeba się przyjrzeć konfigowi USB host w mikrokontrolerze współpracującym z pendrive'm?
    Masz w programie linię
    Kod: c
    Zaloguj się, aby zobaczyć kod

    gdy zegar mikrokontrolera jest z PLL?
  • #47
    mrh
    Poziom 18  
    Ja mam tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Przejrzą konfigurację USB Host i może jeszcze ulepszę kod i może będzie lepiej działać.
  • #48
    mrh
    Poziom 18  
    Po moich przeróbkach jest jeszcze gorzej z odtwarzanie mp3 320kb/s, zacina odtwarzanie tak jak by uC nie wyrabiał z dekodowanie mp3.
    Najważniejszy kawałek kodu wygląd tak:
    - pobieranie danych z karty:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    - dekodowanie mp3:
    Kod: c
    Zaloguj się, aby zobaczyć kod



    Może ma ktoś jakieś sugestię jak to zoptymalizować ?
  • #49
    Tytus Kosiarski
    Poziom 15  
    Mam pytanie-propozycję: Czy możesz wrzucić do pamięci Flash mikrokontrolera tablicę uint8_t w której jest problematyczny kawałek MP3 320kb/s? Niech read_pointer z Twojej funkcji mp3_process wskazuje na początkowy bajt tej tablicy we Flash. Pozbywamy się w ten sposób problemów wynikających z (być może) błędnej obsługi / odczytu karty SD.
    Drugie moje pytanie: Czy tablica wskazywana przez out_buffer w tej samej funkcji jest typu int16_t? Oraz, czy rozmiar tej tablicy w Twoim przypadku jest równy MAX_NCHAN * MAX_NGRAN * MAX_NSAMP * 2 (bo w jednej tablicy out_buffer mieścisz dwie zdekodowane próbki)?
  • #50
    mrh
    Poziom 18  
    Próbowałem już umieszczać kawałek mp3 we Flash'u i działa jak należy, ale w ten sposób omijam cały odczyt z pendrajwa, który zapewne też pochłania trochę pracy uC.
    Rozmiar out_buffer wynosi 4608.

    W internecie znalazłem projekt, który też pobiera dane z pendrajwa i utwory mp3 320kb/s spokojnie odtwarza.

    Może bym do współpracy wciągną FreeRTOS.
  • #51
    Tytus Kosiarski
    Poziom 15  
    Dobrze. W takim razie spróbuj następną rzecz: pomiń pośrednictwo FatFS (bo wydaje mi się, że z tego korzystasz). Zamiast tego spróbuj bezpośrednio odczytywać dane z karty lub pendrive. Żeby pominąć FAT, to można ten plik MP3 nagrać na pustą kartę sektor po sektorze np. przy pomocy windowsowego dskprobe.exe i potem tak samo odczytywać w odtwarzaczu. Sprawdzisz wtedy interfejs między nośnikiem danych i mikrokontrolerem, natomiast pominiesz obliczenia wykorzystujące dane w tablicy FAT i związane z wynajdywaniem klastrów zajętych przez plik. Jeśli by Ci to pomogło, to mogę podesłać programik zapisujący i odczytujący kartę SD (interfejs SDIO, tryb DMA lub polling).
  • #52
    mrh
    Poziom 18  
    Po wielkich trudach udało mi się pominąć system plików. Efekt jest znakomity mp3 320kb/s śmiga aż miło słuchać.