12/25/2012

Ultra szybki JSON, czyli ujson

Kilkanaście godzin temu natknąłem się na moduł ujson, który jest napisany w czystym C i może pochwalić się niebywałą szybkością :) Mimo, iż na stronie modułu są przedstawione testy z trzema innymi popularnymi modułami, sam również postanowiłem to sprawdzić.

Moduł ujson porównałem ze standardowym modułem w pythonie, czyli json.

Dane testowe

Pierwsze dane to obiekt, z którym możemy się najczęściej spotkać przy codziennej pracy z różnego rodzaju api, natomiast do drugich danych wpisałem po prostu to co przyszło mi do głowy ;)
test_data1 = {'status': True, 'msg': 'Message'}
test_data2 = [{'name': 'tomislater', 'age': 24, 'sex': 'male'}, 8461, True, False, 8923, 7162, 1, 6, 7, None, [[True, False], ['!', '?']], 'yeah']

Serializacja do formatu JSON

Do porównania obu bibliotek stworzyłem cztery funkcję. Po dwie do każdej.
def test_json_data1():
    return json.dumps(test_data1)

def test_ujson_data1():
    return ujson.dumps(test_data1)

def test_json_data2():
    return json.dumps(test_data2)

def test_ujson_data2():
    return ujson.dumps(test_data2)
Do mierzenia czasu skorzystałem z modułu timeit ze standardowej biblioteki pythona. Każda funkcja została wywołana milion razy:
json_data1 = timeit.timeit("test_json_data1()", setup="from __main__ import test_json_data1", number=1000000)

ujson_data1 = timeit.timeit("test_ujson_data1()", setup="from __main__ import test_ujson_data1", number=1000000)

json_data2 = timeit.timeit("test_json_data2()", setup="from __main__ import test_json_data2", number=1000000)

ujson_data2 = timeit.timeit("test_ujson_data2()", setup="from __main__ import test_ujson_data2", number=1000000)

Wyniki testów dla serializacji do formatu JSON:

Jak widać, jeżeli chodzi o serializację obiektów, moduł ujson jest o wiele szybszy od standardowego modułu.

Deserializacja z formatu JSON

Sprawdźmy teraz jak oba modły radzą sobie z deserializacją:
test_data1 = '{"status": true, "msg": "Message"}'
test_data2 = '[{"age": 24, "name": "tomislater", "sex": "male"}, 8461, true, false, 8923, 7162, 1, 6, 7, null, [[true, false], ["!", "?"]], "yeah"]'

def test_json_data1():
    return json.loads(test_data1)

def test_ujson_data1():
    return ujson.loads(test_data1)

def test_json_data2():
    return json.loads(test_data2)

def test_ujson_data2():
    return ujson.loads(test_data2)

json_data1 = timeit.timeit("test_json_data1()", setup="from __main__ import test_json_data1", number=1000000)
ujson_data1 = timeit.timeit("test_ujson_data1()", setup="from __main__ import test_ujson_data1", number=1000000)
json_data2 = timeit.timeit("test_json_data2()", setup="from __main__ import test_json_data2", number=1000000)
ujson_data2 = timeit.timeit("test_ujson_data2()", setup="from __main__ import test_ujson_data2", number=1000000)
Wyniki testów dla deserializacji z formatu JSON:

Jak widać twórcy nie kłamią, moduł ten jest naprawdę szybki! Należy jednak pamiętać, że testy to jedno, a praktyka to drugie, dlatego też w najbliższym czasie skorzystam z ów modułu i postaram się podzielić obserwacjami.

Wesołych świąt!

12/22/2012

Anki nie odtwarza plików wav

Ostatnio wraz ze zmianą laptopa zmieniłem również system operacyjny z Fedory na Ubuntu. Po zainstalowaniu Anki i zaimportowaniu swojego profilu mogłem zacząć naukę. Przeleciałem kilka decków, wszystko fajnie działa, odtwarza pliki mp3, pokazuje obrazki etc. Lecz na jednym z decków za cholerę nie chciał odtworzyć plików wav.

Info przykładowego pliku:
PerfectP(100).wav
Codec: MPEG 1 Audio, Layer 3 (MP3)
Channels: Mono
Sample rate: 44100 Hz
Bitrate: 63 kbps

No dobra, pewnie nie mam potrzebnych kodeków. Poinstalowałem co trzeba, nadal nic... Co ciekawe w każdym programie do odtwarzania muzyki, pliki te działały. Czyli kodeki mam, to nie ich wina.

To spróbuję dowiedzieć się coś o tym pliku przez soxa:
>> soxi PerfectP\ \(100\).wav
soxi FAIL formats: can't open input file `PerfectP (100).wav': WAV file encoding `MP3' is not supported

Acha. Ciekawie się zaczyna. To może uda mi się go odtworzyć, próbuję:
>> play PerfectP\ \(100\).wav
play FAIL formats: can't open input file `PerfectP (100).wav': WAV file encoding `MP3' is not supported

To samo. W sumie to się tego spodziewałem. Czyli co? MP3 is not supperted. Jak nie, jak specjalnie skompilowałem wcześniej soxa, aby wspierał prawie każdy format audio... Coś tutaj jest nie tak. Zabieram się za grzebanie w kodzie Anki. Od razu otworzyłem plik sound.py w katalogu /usr/share/anki/libanki/anki/.

Okej, czyli Anki korzysta z mplayera. To spróbujemy otworzyć plik za pomocą mplayera:
>> mplayer PerfectP\ \(100\).wav 
MPlayer svn r34540 (Ubuntu), built with gcc-4.6 (C) 2000-2012 MPlayer Team
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.

Playing PerfectP (100).wav.
libavformat version 53.21.0 (external)
Mismatching header version 53.19.0
Audio only file format detected.
Load subtitles in ./
==========================================================================
Requested audio codec family [mpg123] (afm=mpg123) not available.
Enable it at compilation.
Opening audio decoder: [ffmpeg] FFmpeg/libavcodec audio decoders
libavcodec version 53.35.0 (external)
Mismatching header version 53.32.2
[mp3float @ 0x7f53bd067380]Header missing
[mp3float @ 0x7f53bd067380]Header missing
Unknown/missing audio format -> no sound
ADecoder init failed :(
Opening audio decoder: [ffmpeg] FFmpeg/libavcodec audio decoders
Unknown/missing audio format -> no sound
ADecoder init failed :(
Requested audio codec family [mad] (afm=libmad) not available.
Enable it at compilation.
Requested audio codec family [mp3acm] (afm=acm) not available.
Enable it at compilation.
Opening audio decoder: [hwmpa] MPEG audio pass-through (fake decoder)
Cannot sync MPA frame: 0
ADecoder init failed :(
ADecoder init failed :(
Opening audio decoder: [spdif] libavformat/spdifenc audio pass-through decoder.
AUDIO: 48000 Hz, 2 ch, mpeg2, 768.0 kbit/50.00% (ratio: 96000->192000)
Selected audio codec: [spdifmpa] afm: spdif (libavformat/spdifenc MPEG AUDIO BC pass-through decoder)
==========================================================================
AO: [pulse] 48000Hz 2ch s16le (2 bytes per sample)
[format] Sample format big-endian MPEG-2 not yet supported 
[libaf] Reinitialization did not work, audio filter 'format' returned error code -2
[libaf] Unable to setup filter system can not meet sound-card demands, please send a bug report. 
Couldn't find matching filter/ao format!
Audio: no sound
Video: no video


Exiting... (End of file)

No tak, czyli o co chodzi w końcu? Zaczęło się szperanie po necie i szukanie rozwiązania. Po przestudiowaniu  man-sox znalazłem coś takiego:
-t, --type file-type 
Gives the type of the audio file. This is useful when the file extension is non-standard or when the type can not be determined by looking at the header of the file. The -t option can also be used to override the type implied by an input filename extension, but if overriding with a type that has a header, SoX will exit with an appropriate error message if such a header is not actually present.

O, to spróbuję tego!
>> play -t mp3 PerfectP\ \(100\).wav 
play WARN mp3-util: MAD lost sync

PerfectP (100).wav:

 File Size: 9.26k     Bit Rate: 64.0k
  Encoding: MPEG audio    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.16  

In:94.7% 00:00:01.10 [00:00:00.06] Out:48.4k [      |      ] Hd:4.4 Clip:0    
Done.

Działa! No dobra, to teraz trzeba zmusić mplayera, aby wymuszał najpierw mp3, a potem całą resztę i powinno zadziałać ;)
>> mplayer -ac mp3 PerfectP\ \(100\).wav 
MPlayer svn r34540 (Ubuntu), built with gcc-4.6 (C) 2000-2012 MPlayer Team
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.

Playing mp3.
File not found: 'mp3'
Failed to open mp3.


Playing PerfectP (100).wav.
libavformat version 53.21.0 (external)
Mismatching header version 53.19.0
Audio only file format detected.
Load subtitles in ./
==========================================================================
Forced audio codec: mp3
Opening audio decoder: [mp3lib] MPEG layer-2, layer-3
AUDIO: 44100 Hz, 2 ch, s16le, 64.0 kbit/4.54% (ratio: 8000->176400)
Selected audio codec: [mp3] afm: mp3lib (mp3lib MPEG layer-2, layer-3)
==========================================================================
AO: [pulse] 44100Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
A:   0.9 (00.8) of 1.0 (01.0)  0.2% 


Exiting... (End of file)

Yeah! Teraz wystarczy pogrzebać kodzie Anki i dodać komendę -ac mp3. Otwieram plik /usr/share/anki/libanki/anki/sound.py (w najnowszej wersji: /usr/share/anki/anki/sounds.py), przechodzę do linii numer 72 i rozszerzam listę ukrywającą się pod zmienną mplayerCmd o dwa dodatkowe obiekty typu string:
mplayerCmd += ["-really-quiet", "-noautosub", "-ac", "mp3"]

Lub można prościej, edytując pliki konfiguracyjne mplayera. Wystarczy, że do pliku ~/.mplayer/config dodasz linijkę:
ac="mp3"
Zapisuję, odpalam Anki i uczę się dalej ;) Jak ktoś miał podobny problem i rozwiązał go inaczej to zapraszam do dyskusji, co ciekawe bez grzebania w kodzie pod Fedorą wszystko mi działało jak trzeba. Myślałem, że trzeba skompilować mplayera jeszcze raz, ale to też nie pomagało.

Brak flagi xterm_clipboard w vimie pod ubuntu

Jeżeli pod Ubuntu zainstalowałeś vima poprzez sudo apt-get install vim system zainstalował tobie tak naprawdę vim-tiny, który jest lekko okrojony. Np. nie ma ustawionej flagi xterm_clipboard, która bardzo się przydaje przy kopiowaniu. Możesz oczywiście skompilować vima z tą flagą albo wykonać polecenie sudo apt-get install vim-gnome lub vim-gtk, które zainstaluje rozszerzonego vim'a i zapewni ci między innymi ustawioną flagę xterm_clipboard. Nie musisz usuwać vim-tiny.

Krzaki w powerline

Jeżeli używasz powerline-bash czy vim-powerline i w konsoli masz krzaki. Tutaj znajdziesz rozwiązanie ;). Skopiuj czcionkę z której korzystasz do /usr/share/fonts/trutype i to wszystko. Osobiście polecam Source Code Pro lub Droid Sans Mono.

12/05/2012

Kill Spiders 0.2.1

Miałem trochę wolnego czasu więc dodałem kilka rzeczy do repo. Dodałem bonusy polegające na tym, że gracz rzuca nie jedną, a dwiema lub trzema czaszkami jednocześnie. Im silniejszego pająka zabijesz tym większe prawdopodobieństwo, że otrzymasz bonus ;)
Poprawiłem zapisywanie highscore, nie wiedzieć czemu gdy program wychodził z głównej pętli nie wykonywał zapisu do pliku :/
Zwiększyłem liczbę "specjalnych" pająków oraz zmieniłem liczbę czarnych czaszek które gracz otrzymuje za kolejny poziom z jednej na pięć.
Na końcu jak zawsze lekka refaktoryzacja kodu ;)

Chętnych zapraszam tutaj: kill_spiders

Grę odpalasz komendą:
python start_game.py