23 maj 2009

Samsung yp-u1

Dziś będzie trochę inna notka, nie nawiązująca zbyt wiele do programowania. Jak widać, znajduje się w kategorii krótka recenzja, lecz nie będę tu opisywał kolejnej, niezwykle fascynującej książki, z wciągającą fabułą i akcją. Chciałbym opisać niewielkie urządzenie, z którym miałem przyjemność spędzić ostatnie 3 lata. Nie jest to już więc sprzęt najnowszy, raczej ciężko go dziś kupić, jednak po tylu latach użytkowania chciałbym napisać kilka spostrzeżeń na temat tego niewielkiego odtwarzacza mp3.

Na początek kilka podstawowych danych technicznych:

  • wymiary: 25.6 x 87.4 x 13.6 mm
  • waga: 33g
  • zakres częstotliwości: 20Hz~20KHz
  • czas odtwarzania: 13h (wbudowany akumulator litowo-polimerowy)

Jak więc widać, jest to dość zgrabne i lekkie urządzenie. Dodatkowo bez problemów radzi sobie z formatami mp3 (także ze zmiennym bitrate) ogg, wma czy wav. Raz tylko zdarzył mi się plik, który podczas odtwarzania zawiesił odtwarzacz. Komunikacja z komputerem została rozwiązana standardowo: port USB 2.0, choć sposób chowania konektora jest nieco oryginalny (o tym później). Wyświetlacz jest cztero linijkowy, podświetlany w razie potrzeby na biało. Prezentowany tekst jest wyraźny i ostry. Nawet podczas przesuwania nie miga ani nie smuży, co często się zdarza w odtwarzaczach tego typu. Podświetlenie także nie pozostawia nic do życzenia – równomiernie rozłożone na całość ekranu.

Posiadana przeze mnie wersja miała 512MB (YP-U1X), lecz dostępna ilość miejsca do zayp-u1_blgpisu to 496MB.
Nawigacja po menu zostało zrobiona w sposób bardzo intuicyjny, szczególnie, że całość została przetłumaczona na język polski. Co ciekawe, “nieprzetłumaczalne” jest tylko “Settings” i “Language”, by po zmianie języka na koreański, bez problemów można było przywrócić stare ustawienia.
Główny ekran odtwarzania jest mocno konfigurowalny. Bez problemów można wyświetlić informacje na temat trybu odtwarzania, włączonego efektu dźwiękowego, bitrate (pliki ze zmiennym są oznaczane jako VBR), numeru pliku i poziomu baterii. Ciekawą opcją są dwa sposoby przewijania nazw utworów: poziomy i pionowy. Ten ostatni jest szczególnie przydatny, gdy nazwa piosenki jest dość długa by w krótkim czasie mogła zostać zaprezentowana w całości.
Nawigacja po drzewie plików też nie przysporzyła mi nigdy problemów – całość rozwiązana standardowo i intuicyjnie. Niektórym osobom nie podobał się sposób włączania  i wyłączania odtwarzacza: kilku sekundowe przytrzymanie przycisku Play. Przyznam, że nigdy nie miałem problemów z przypadkowym wyłączeniem playera, tym bardziej, że czas reakcji jest dość szybki, a dodatkowo jest możliwość włączenia “brzęczyka” – dźwiękowe informowanie o wciśniętych przyciskach. Odtwarzacz obsługuje także własny typ playlist. Nie korzystałem z nich jednak nigdy; wolałem standardową, “folderową” kolejność utworów.
Dodatkową opcją jest nagrywanie dźwięku, lecz należy traktować to jako dodatek. Jakość nagrań jest  bardzo zła, poza tym, zapisywane sa tylko w formacie wav.

Zewnętrznie urządzenie zostało wykonane dość estetycznie. Warto zauważyć, że, wbrew pozorom, jest to bardzo mocna konstrukcja. Nie raz zdarzyło mi się, że podczas wyciągania telefonu z kieszeni, wypadł mi także player – działa do dziś.

Wyżej wspominałem o ciekawym rozwiązaniu dotyczącym chowania wtyczki USB. Pierwszy raz spotkałem się z takim podejściem do problemu, by zamiast wysuwania, zastosować składanie – jest to ostatni (jeśli nie jedyny) model odtwarzacza mp3 Samsunga, który stosuje taki sposób. Niestety, po 3 latach intensywnego użytkowania (także często jako przenośna pamięć) rozwiązanie takie nie sprawdziło się. Jeśli przez pierwszy okres używania Yeepa nie było żadnych problemów, to teraz (zauważyłem to kilka miesięcy temu) urządzenie nie łączy się z komputerem w kilku warunkach. Przede wszystkim wejście USB nie może być zamontowane poziomo. Wówczas odtwarzacz opada (konektor się składa) i traci kontakt z komputerem – widać jakieś ruchome części odpowiedzialne za łączenie zostały uszkodzone. 
Warto także zaznaczyć, że nie należy doprowadzać do zerowego stanu baterii. Często jest tak, że mimo informacji o niskim stanie akumulatora, po kilku chwilach odtwarzacz może zagrać jeszcze jeden, czy dwa utwory. Jest to jednak nie zalecane postępowanie. Ogólnie bateria sprawuje się dość dobrze – aktualnie trzyma od 6 do 8 godzin ciągłego odtwarzania muzyki. Warto zaznaczyć, że podświetlanie jest dość mocno “proądożerne” :)

Dołączone w zestawie słuchawki są wykonane solidnie i charakteryzują się dobrą jakością dźwięku podobnie jak sam odtwarzacz – nie jestem jednak znawcą i audiofilem, więc opinie będą na ten temat różne.       

Podsumowując: YP-U1 to solidnie, proste w obsłudze, dobrze wykonane urządzenie nie pozbawione jednak kilku wad. Bez problemu zmieści sie w kieszeni i pozwoli posłuchać ulubionej muzyki w prawie każdych warunkach.

20 maj 2009

SSE w praktyce - #1

Dziś postaram się przedstawić podstawowe operacje jakie możemy wykonać przy użyciu multimedialnych rozszerzeń procesora. Pokażę możliwość bezpośredniego wykorzystania assemblera, zaś w następnych notkach skupię się na wewnętrznych poleceniach kompilatora, specjalnie przygotowanych do obsługi SSE. Aby prezentowany kod mógł zostać uruchomiony potrzebny jest procesor klasy Intel Pentium III lub lepszy.
Więc do dzieła ;)

Jednak, jak to zwykle bywa, na początek jeszcze trochę teorii.
Programując przy użyciu SSE mamy do dyspozycji 8 dodatkowych, 128 bitowych rejestrów (w przypadku kodu dla procesorów 64 bitowych, liczba ta zwiększa sie do 16) - od xmm0 do xmm7. Wszystkie operacje, jakie będziemy chcieli wykonać przy użyciu omawianych tu instrukcji multimedialnych, będą operować właśnie na tych rejestrach. Jak już wiadomo, każdy z nich może przechować 4 wartości zmiennoprzecinkowe pojedynczej precyzji (float).

Na początek przygotujmy dane na których będziemy pracować: czteroelementowa, jednowymiarowa, wyrównana do 128 bitów tablica typu float – czyli nasz wektor.

__declspec(align(16)) float gVector4[4];
Zobaczmy na początek, w jaki sposób możemy dostać się do danych naszego wektora. Nie będziemy tego robić standardowo,
za pomocą operatora [ ] – posłużymy się do tego odpowiednimi instrukcjami SSE.
Pierwszą podstawową rzeczą, będzie skopiowanie zawartości komórki pamięci, gdzie znajduje się nasz wektor, do rejestru xmm.
_asm{
    lea esi,gVector4
    movaps xmm0,[esi]
    //wykonaj operacje...
    movaps [esi],xmm0
}
Pierwsza linijka odpowiada za pobranie adresu zmiennej gVector4 (dokładny opis działania instrukcji lea można znaleźć tu)
i skopiowanie go do rejestru esi (wskaźnik danych).
Następnie możemy zobaczyć już instrukcję z rodziny SSE –
movaps. Odpowiada ona za kopiowanie zawartości rejestrów xmm
między sobą, a także pamięcią. W tym przypadku, zawartość komórki pamięci na który wskazuje rejestr esi, zostanie przesłana do rejestru xmm0.
Ostatnia instrukcja kopiuje zawartość rejestru xmm0 pod adres wskazywany przez esi – czyli do naszej zmiennej.
Jak widać, mimo że jest to assembler, nie jest to takie trudne. Wygenerujmy więc nieco więcej bardziej praktycznego kodu.
Jak pewnie zważyliście, deklarowanie za każdym razem owej specyficznej tablicy z pewnością nie należy do specjalnie wygodnych.
Uprośćmy więc nieco ten proces:
typedef __declspec(align(16)) float AlignedVector4D[4];
Ten niewielki kawałek kodu, z pewnością pozytywnie wpłynie na czytelność kodu.
Poznajmy więc kilka podstawowych operacji: dodawanie, odejmowanie, mnożenie i dzielenie.
Na początek zdefiniujmy dwa wektory, na których będziemy wykonywać nasze operacje:
AlignedVector4D vec1 = {5.0,6.0,3.0,1.0};
AlignedVector4D vec2 = {2.5,3.0,1.5,0.5};

Za dodawanie odpowiada instrukcja addps. Przykład użycia:
_asm{
    lea esi,[vec1];
    lea edi,[vec2];

    movaps xmm0,[esi];
    movaps xmm1,[edi];

    addps xmm0,xmm1;

    movaps [esi],xmm0
}
Jak widać kod jest bardzo prosty. Dwie początkowe instrukcje odpowiadają za pobranie adresu zmiennych, następnie kopiujemy je
do rejestrów xmm0 oraz xmm1 by dodać je do siebie w następnej instrukcji. Wynik zapisywany jest do xmm0 które jest kopiowane
pod adres jaki wskazuje esi, czyli do zmiennej vec1.
Zauważmy, że obecność kopiowania do rejestru xmm1 nie jest konieczna – addps, podobnie jak movaps może pracować na jednym
operandzie znajdującym sie w pamięci operacyjnej:
_asm{
    lea esi,[vec1];
    lea edi,[vec2];

    movaps xmm0,[esi];
    addps xmm0,[edi];
    movaps [esi],xmm0
}
Pozostałe operacje wykonuje się analogicznie:
subps – odejmowanie
mulps – mnożenie
divps – dzielenie
To byłoby na tyle. W kolejnych częściach poznamy trochę więcej interesujących rzeczy ;)