jeudi 21 mai 2009

Musique : Playing For Change

Je ne sais pas si les plus surfeurs d'entre vous connaissent ce site mais c'est juste un must have : Playing For Change.
L'idée est simple : aller à la rencontre d'inconnus, tout autour du monde, souvent ils s'agit de ces gens que l'on rencontre dans le métro, les gares ou en plein centre ville avec leur guitare ou juste leur voix.
Vient l'idée d'aller à leur rencontre avec pour objectif de produire des musiques prônant la paix via leurs musiques en mixant l'interprétation de chacun, individuellement, les vidéos vous parleront plus.
Ma foi, je doit dire que le but est "quelque peu" atteint, deux vidéos prises au hasard car elles sont toutes ... magnifiques.



mardi 19 mai 2009

Programmation : 2ème partie, de l'importance de l'optimisation

Suite de ce billet, on va rentrer dans le vif du sujet.
Je ne vais pas détailler l'algorithme mais le code doit calculer les 16 points permettant de calculer l'amplitude finale, cela consiste donc à multiplier chaque point source par l'échantillon et à multiplier chaque point de destination par le sample, à ce stade, nous avons les deux amplitudes (source et destination), il ne reste plus qu'à calculer l'amplitude qui consiste à obtenir la distance entre ces deux points (+ partie fractionnelle).
Voici le code original, en PureBasic, oui je sais, inconnu au bataillon tout ça mais peu importe, n'importe quel programmeur devrait comprendre le code, plutôt simple :

#FP_SHIFT = 15

; init sinc table
SAMPLE_init_sinc_table()

; init sample data
*sample_data = AllocateMemory(16 * 2)

; init mix buffer (4 samples)
; LR - LR - LR - LR
*mix_buffer = AllocateMemory(8 * SizeOf(Long))

; alimentation de données bidon
PokeW(*sample_data + 0, 10)
PokeW(*sample_data + 2, 20)
PokeW(*sample_data + 4, 30)
PokeW(*sample_data + 6, 40)
PokeW(*sample_data + 8, 50)
PokeW(*sample_data + 10, 60)
PokeW(*sample_data + 12, 70)
PokeW(*sample_data + 14, 80)

PokeW(*sample_data + 16, 90)
PokeW(*sample_data + 18, 100)
PokeW(*sample_data + 20, 110)
PokeW(*sample_data + 22, 120)
PokeW(*sample_data + 24, 130)
PokeW(*sample_data + 26, 140)
PokeW(*sample_data + 28, 150)
PokeW(*sample_data + 30, 160)


size_of_word = SizeOf(Word)
table_idx = 0
sample_idx = 0
offset = 0
left_gain = 2408
right_gain = 5156

start0 = GetTickCount_()
For i = 0 To 10000000

While offset < 8

*sinc_table_ptr = *sinc_table + ( ( table_idx + 0 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 0) * size_of_word )
a1 = (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 16) * size_of_word )
a2 = (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 1 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 1) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 17) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 2 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 2) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 18) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 3 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 3) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 19) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 4 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 4) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 20) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 5 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 5) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 21) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 6 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 6) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 22) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 7 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 7) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 23) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 8 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 8) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 24) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 9 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 9) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 25) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 10) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 10) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 26) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 11) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 11) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 27) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 12) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 12) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 28) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 13) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 13) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 29) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 14) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 14) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 30) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

*sinc_table_ptr = *sinc_table + ( ( table_idx + 15) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 15) * size_of_word )
a1 + (*sinc_table_ptr\w * *sample_data_ptr\w)
*sinc_table_ptr = *sinc_table + ( ( table_idx + 31) * size_of_word )
a2 + (*sinc_table_ptr\w * *sample_data_ptr\w)

a1 >> #FP_SHIFT
a2 >> #FP_SHIFT

; SIMPLIFICATION du code (code bidon, ne fonctionne pas)
amplitude = a1 + a2

*mix_buffer_ptr = *mix_buffer + (offset * SizeOf(Long))
newsample = (amplitude * left_gain) >> #FP_SHIFT
*mix_buffer_ptr\l + newsample

*mix_buffer_ptr = *mix_buffer + ((offset + 1) * SizeOf(Long))
newsample = (amplitude * right_gain) >> #FP_SHIFT
*mix_buffer_ptr\l + newsample

offset + size_of_word

; fake sinc table_idx
table_idx + 1

;Debug "SINC_NO_SSE:: A1 = " + Str(a1) + " A2 = " + Str(a2)

Wend

offset = 0
table_idx = 0
sample_idx = 0
Next i
end0 = GetTickCount_()

; result of mixing
amp1 = PeekL(*mix_buffer + 0 * SizeOf(long) )
amp2 = PeekL(*mix_buffer + 1 * SizeOf(long) )
amp3 = PeekL(*mix_buffer + 2 * SizeOf(long) )
amp4 = PeekL(*mix_buffer + 3 * SizeOf(long) )
amp5 = PeekL(*mix_buffer + 4 * SizeOf(long) )
amp6 = PeekL(*mix_buffer + 5 * SizeOf(long) )
amp7 = PeekL(*mix_buffer + 6 * SizeOf(long) )
amp8 = PeekL(*mix_buffer + 7 * SizeOf(long) )

Debug "SINC_NO_SSE:: SSE_CALC amp1 = " + Str(amp1) + " amp2 = " + Str(amp2) + " amp3 = " + Str(amp3) + " amp4 = " + Str(amp4)
Debug "SINC_NO_SSE:: SSE_CALC amp5 = " + Str(amp5) + " amp6 = " + Str(amp6) + " amp7 = " + Str(amp7) + " amp8 = " + Str(amp8)



Explication :
- initialisation d'un tableau contenant les points pré calculés pour des échantillons sur 16 bits ( SAMPLE_init_sinc_table() ),
- allocation d'un tampon contenant les échantillons en entrée (8 échantillons car un échantillons occupe 2 octets * 2 car il est stéréo au format LR (Left - Right) ),
- allocation d'un tampon en sortie au format entier pour stocker pour un entier, l'échantillon stéréo donc un int contient deux shorts (LR),
- alimentation via des données bidons (les PokeW(*sample_data + 0, 10) ... ),
- initialisation de différentes valeurs pour le test,
- puis vient la partie critique, on boucle 10000000 (pour le bench), à chaque itération, nous bouclons 8 fois pour récupérer 2*8 shorts d'échantillons qui seront stockés dans notre tampons de mixage, pour chaque itération, nous calculons le point source et destination, je le scale sur 16 bits (-1 pour le bit de signe) et je stocke le tout dans le mélangeur.

Un gros pâte pour finalement pas grand chose.
Maintenant, voyons ce que ça donnerais en SSE2 :

Procedure.l PB_sse2_mul_add(*p1.Word, *p2.Word, size.l)
Protected *dest_buffer_ptr.Long
Protected idx.l, size_of_elements = size / 8

*dest_buffer_ptr = @dest_buffer()

!MOV esi, [p.p_p1]
!MOV edi, [p.p_p2]
!MOV edx, [p.p_dest_buffer_ptr]
!XOR ecx, ecx
!PXOR xmm4, xmm4

For idx = 0 To size_of_elements - 1
!MOVUPS xmm0, [esi+ecx] ; +16
!MOVUPS xmm1, [esi+ecx] ; +16

!MOVUPS xmm2, [edi+ecx] ; +16

!PMULLW xmm0, xmm2
!PMULHW xmm1, xmm2

!MOVUPS xmm3, xmm0 ; copy orig xmm0

!PUNPCKLWD xmm0, xmm1 ; xmm0 --> loword (this is why it is was copied :p )
!PUNPCKHWD xmm3, xmm1

!PADDD xmm4, xmm0
!PADDD xmm4, xmm3

!MOVUPS [edx], xmm4

!ADD ecx, 16
Next idx

result = PeekL(*dest_buffer_ptr) + PeekL(*dest_buffer_ptr+4) + PeekL(*dest_buffer_ptr+8) + PeekL(*dest_buffer_ptr+12)

ProcedureReturn result
EndProcedure

;- calc amplitude 0
*sinc_table_ptr = *sinc_table + ( ( table_idx + 0 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 0) * size_of_word )

a1 = PB_sse2_mul_add(*sinc_table_ptr, *sample_data_ptr, 16)
a2 = PB_sse2_mul_add(*sinc_table_ptr+32, *sample_data_ptr, 16)

a1 >> #FP_SHIFT
a2 >> #FP_SHIFT

calc_amp(0) = a1 + a2

; fake sinc table_idx
table_idx + 1

Debug "SINC_SSE:: A1 = " + Str(a1) + " A2 = " + Str(a2)

;- calc amplitude 1
*sinc_table_ptr = *sinc_table + ( ( table_idx + 0 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 0) * size_of_word )

a1 = PB_sse2_mul_add(*sinc_table_ptr, *sample_data_ptr, 16)
a2 = PB_sse2_mul_add(*sinc_table_ptr+32, *sample_data_ptr, 16)

a1 >> #FP_SHIFT
a2 >> #FP_SHIFT

calc_amp(1) = a1 + a2

; fake sinc table_idx
table_idx + 1

;- calc amplitude 2
*sinc_table_ptr = *sinc_table + ( ( table_idx + 0 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 0) * size_of_word )

a1 = PB_sse2_mul_add(*sinc_table_ptr, *sample_data_ptr, 16)
a2 = PB_sse2_mul_add(*sinc_table_ptr+32, *sample_data_ptr, 16)

a1 >> #FP_SHIFT
a2 >> #FP_SHIFT

calc_amp(2) = a1 + a2

; fake sinc table_idx
table_idx + 1

;- calc amplitude 3
*sinc_table_ptr = *sinc_table + ( ( table_idx + 0 ) * size_of_word )
*sample_data_ptr = *sample_data + ( ( sample_idx + 0) * size_of_word )

a1 = PB_sse2_mul_add(*sinc_table_ptr, *sample_data_ptr, 16)
a2 = PB_sse2_mul_add(*sinc_table_ptr+32, *sample_data_ptr, 16)

a1 >> #FP_SHIFT
a2 >> #FP_SHIFT

calc_amp(3) = a1 + a2

; fake sinc table_idx
table_idx + 1

*calc_amp_ptr = @calc_amp(0)
*mix_buffer_ptr = *mix_buffer + (0 * SizeOf(Long))
*left_gain_ptr = @left_gain
*right_gain_ptr = @right_gain

; sse mixing

; L - L - L - L
; 159 - 139 - 119 - 99
;* 2048 - 2048 - 2048 - 2048
; ---- ----- ----- -----
;325632 284672 243712 202752

; R - R - R - R
; 159 - 139 - 119 - 99
;* 5156 - 5156 - 5156 - 5156
; ---- ----- ----- -----
; 819804 716684 613564 510444

start1 = GetTickCount_()
For i = 0 To 10000000

!MOV esi, [p_calc_amp_ptr]
!MOV edi, [p_mix_buffer_ptr]
!MOV ebx, [p_left_gain_ptr]
!MOV edx, [p_right_gain_ptr]
!PXOR xmm0, xmm0
; !PXOR xmm1, xmm1
!PXOR xmm2, xmm2
!PXOR xmm3, xmm3
!PXOR xmm4, xmm4
; !PXOR xmm5, xmm5

; store
!MOVUPS xmm0, [esi] ; amp0 - amp1 - amp2 - amp3 (LLLL)
!MOVUPS xmm4, xmm0 ; amp0 - amp1 - amp2 - amp3 (RRRR)
!MOVUPS xmm1, [edi] ; sample0 - sample1 - sample2 - sample3
!MOVUPS xmm5, [edi+16] ; sample4 - sample5 - sample6 - sample7
!MOVUPS xmm2, [ebx] ; ? - ? - ? - left_gain
!MOVUPS xmm3, [edx] ; ? - ? - ? - right_gain

; prepare shift
!PSHUFD xmm2, xmm2, 00b ; left_gain - left_gain - left_gain - left_gain
!PSHUFD xmm3, xmm3, 00b ; right_gain - right_gain - right_gain - right_gain

; calc amplitude
!cvtdq2ps xmm2, xmm2 ; int --> single
!cvtdq2ps xmm3, xmm3 ; int --> single

!cvtdq2ps xmm0, xmm0 ; int --> single
!cvtdq2ps xmm4, xmm4 ; int --> single

; perform 4 singles mul (LLLL)
!mulps xmm0, xmm2 ; amp0*left_gain - amp1*left_gain - amp2*left_gain - amp3*left_gain (create LLLL sample)
; perform 4 singles mul (RRRR)
!mulps xmm4, xmm3 ; amp0*right_gain - amp1*right_gain - amp2*right_gain - amp3*right_gain (create RRRR sample)

!cvtps2dq xmm0, xmm0
!cvtps2dq xmm4, xmm4

; calc fractional bits
!PSRAD xmm0, 15 ; amp0 >> #FP_SHIFT - amp1 >> #FP_SHIFT - amp2 >> #FP_SHIFT - amp3 >> #FP_SHIFT (LLLL)
!PSRAD xmm4, 15 ; amp0 >> #FP_SHIFT - amp1 >> #FP_SHIFT - amp2 >> #FP_SHIFT - amp3 >> #FP_SHIFT (RRRR)

; save orig values (for low 32 bits word)
!MOVUPS xmm2, xmm0
!MOVUPS xmm3, xmm4

; unpack orig 32 bits low words to saved 32 bits high words (LRLR for 1st sample)
!UNPCKLPS xmm0, xmm4 ; LRLR --> xmm0 (2 samples)
; unpack orig 32 bits high words to saved 32 bits low words (LRLR for 2nd sample)
!UNPCKHPS xmm2, xmm3 ; LRLR --> xmm2 (2 samples)

; mix result : 2 samples mixed at a time
!PADDD xmm1, xmm0
!PADDD xmm5, xmm2

!MOVUPS [edi], xmm1
!MOVUPS [edi+16], xmm5

Next i
end1 = GetTickCount_()

; result of mixing
amp1 = PeekL(*mix_buffer + 0 * SizeOf(long) )
amp2 = PeekL(*mix_buffer + 1 * SizeOf(long) )
amp3 = PeekL(*mix_buffer + 2 * SizeOf(long) )
amp4 = PeekL(*mix_buffer + 3 * SizeOf(long) )
amp5 = PeekL(*mix_buffer + 4 * SizeOf(long) )
amp6 = PeekL(*mix_buffer + 5 * SizeOf(long) )
amp7 = PeekL(*mix_buffer + 6 * SizeOf(long) )
amp8 = PeekL(*mix_buffer + 7 * SizeOf(long) )

Debug "SINC_SSE:: SSE_CALC amp1 = " + Str(amp1) + " amp2 = " + Str(amp2) + " amp3 = " + Str(amp3) + " amp4 = " + Str(amp4)
Debug "SINC_SSE:: SSE_CALC amp5 = " + Str(amp5) + " amp6 = " + Str(amp6) + " amp7 = " + Str(amp7) + " amp8 = " + Str(amp8)


Désolé pour les commentaires mais qu'est ce que cela signifie :
- 1ère différence : c'est LA clef de notre optimisation, on voit que je calcule 4 amplitude en appelant 4 fois la procédure PB_sse2_mul_add(), celle-ci me calcule la partie que j'ai mis en gras plus haut. Cela veut dire que, contrairement au code original, je ne calcule pas qu'une amplitude par itération mais 4 simultanément,
- 2ème différence : je stockais un échantillon au format LR, la, vu que j'ai calculé 4 amplitudes, j'en stocke 4 par itération au format LRLR-LRLR au lieu de LR ... tout court !
- ... et c'est tout !

Mais ces deux simples différences sont éloquentes :
- code PureBasic : 6520 ms en moyenne,
- code SSE2 : 170 ms en moyenne.

Soit 38x plus rapide, rien que ça ! Cela ne se voit pas que dans les benchs mais aussi dans le taux d'occupation cpu : j'oscille entre 2 à 5% (en pique), cela peut sembler encore beaucoup mais c'est tout de même deux fois moins gourmand, objectif réussi :)
Je vous laisse zieuter le code, n'oubliez pas google, c'est grâce à lui que je m'en suis sortie mais je reste disponible pour toute aide que je pourrais apporter :)

Programmation : 1ère partie, de l'importance de l'optimisation

Pas de billet pour annoncer mon come-back mais restons efficace et pour l'annoncer, quoi de mieux qu'un vrai sujet de fond ?
Ici, il s'agira de l'optimisation en programmation, en deux parties histoire de pas avoir un gros pâté.
En effet, à l'heure actuelle, de nombreux langages existent, tous de plus en plus de haut niveau, ayant un niveau d'abstraction, certes on ne s'occupe plus que de l'essentiel mais de fait, on s'éloigne aussi de plus en plus de la machine et donc de sa logique : java, .net, ruby & co n'en sont que quelques exemples.
Dès lors, les programmeurs ont oublié qu'on pouvait optimiser son code, si si, je le vois tous les jours au boulot, nombreux sont ceux qui ne font qu'utiliser tel et tel framework, hop un tour dans la doc, ok, j'utilise ça pour faire ça etc ... mais personne (ou rares) sont les personnes prenant le temps de la réflexion en se disant si son code est vraiment optimisé.
Si j'en parle c'est que j'ai été confronté à cette problématique.
Je code en ce moment une bibliothèque permettant de décoder de la musique au format soundtrack (mod/xm/s3m & co), il y a une partie qui s'occupe de l'interpolation des échantillons, histoire d'"améliorer" le son (ce format induit souvent ce qu'on appel des "clicks & pops" autrement dit des bruits statiques).
J'utilise différents algorithmes ("au plus proche", "linéaire", "cubic spline" et "fir sinc") et c'est ce dernier, très couteux en cpu (16 points sont calculés pour un échantillon) qui m'a fait tiqué.
En effet, j'ai tout bêtement lancé le gestionnaire des tâches pour constater que le cpu oscillait entre 2 et ... 12% !
Inconcevable pour moi, j'ai tout de même un Q9550@3.4 ghz, j'ose imaginer ce que ça donnerais sur un mono core (même si mon code n'est pas optimisé multi-core) ou avec un cpu @1ghz (oui, je me préoccupe de ces machines :) ).
Vient le temps de la réflexion : comment faire pour optimiser ce fameux code ?
Ca a été vite vu car il n'y a pas 30 000 façon de le faire :
- "penser" cpu : c'est à dire arranger son code pour faire en sorte d'être dans la logique de traitement du cpu (exemple : micro fusion, boucle déroulée, prefetch compliancy ...)
- utiliser le SIMD : j'ai déjà lu pas mal de sujer/code à ce sujet mais je ne l'ai jamais réellement utilisé, d'autant plus que je suis loin d'être un guru en assembleur.

N'écoutant que mon courage, la solution la plus viable à mon niveau est ... la seconde ! Oui, j'aime bien les challenges :p

samedi 1 novembre 2008

Demomaking : Kezako ?

Difficile de parler d'un thème lorsque celui ci est vaste, dispose d'une histoire et j'irais même jusqu'à dire qu'il s'agit d'un mouvement culturel au même titre que le hip-hop ou l'art modèrne.
Je vais donc tenter de décrire le démomaking par ces simples mots : il s'agit d'une animation en temps réel qui combine des effets vidéos associés à l'audio.
Ce courant est aussi vieux que l'informatique grand publique (milieu des années 80) et a permis a bon nombres de gens à s'essayer à la programmation.
Les machines ayant nettement évoluées depuis, les programmeurs ne suffisent plus et nous avons des graphistes (2d, 3d, bitmap ou raytracing) , musiciens (mao ou acoustique), scénaristes, designers ... bref, une sorte de mini équipe de développement de jeux vidéos.
D'ailleurs, bon nombre d'entre eux terminent dans ces studios (UbiSoft notamment) et des entreprises sont même créées par eux (Remedy ou plus récemment FurureMark).
Le but n'est pas lucratif, loin de la, tout est bénévole, certains ont même réussi à négocier du temps pendant leur heures de boulots (Chaos de Farbrausch par exemple) pour s'y consacrer, non, le but est juste simple : CREER !
Créer, c'est le maitre mot du démomaker : ce domaine vous interesse mais vous vous dite que vous n'arriverez jamais à faire une démo ou alors qu'elle sera tellement moche qu'on va vous jeter des pierres ? Que nenni ! Vous ne verrez JAMAIS un demomaker, un vrai, ricaner ou se retenir de rire, non, la plupart d'entre eux ont produits des démos qui étaient "pitoyable" graphiquement, à partir du moment ou il y a de création, peu importe ses qualités intrinsèques, l'objectif est atteint.
Il y a de nombreuses sections lors des "compétitions" car oui, il y a énorméments d'évenements où les démomakers se rassemblent pour montrer le fruit de leur travail, Scene.org est un site qui les répertorie, les démos limitées par le temps, d'autres par la taille de l'éxécutable final : 64 ko, 4 ko et même 256 octets !
Si j'en parle c'est juste pour vous montrer ce qu'on peut arriver avec énormément de talents :



Tout ça, dans 4 ko.

Liens utiles :

Vidéo d'un demomaker expliquant mieux que moi ce que je viens de dire : ftp://ftp.scene.org/pub/parties/2008/assembly08/vod/Seminars/628_demo_programming_for_beginners_h264_1856kbit.mp4
Demoscene TV : http://www.demoscene.tv/
Un site qui répertorie aussi les démos mais pas seulement : http://www.pouet.net/
Radio de la demoscene : http://www.scenemusic.eu/demovibes/

vendredi 31 octobre 2008

Sport : nouvelles chaussures

Bon, sans entrer dans le blog kikoololpt2r je raconte ma vie et je mime les raiders (twix pour les plus jeunes) avec mes doigts, c'est juste que je viens de quitter ces chaussures :


On en a vécu des choses : le goudron, les chemins, l'eau, la boue, l'asphalte ... Mais avec le temps, elle commence a accuser le poids des kms, environ 1500, ça ne peut plus continuer, je ne veut plus la faire souffrir.
C'est décidé : je la quitte, et pour de bon !

J'ai rencontré, pas plus tard que ce soir, une bien charmante chaussure que voici :


J'espère que cette fois, c'est la bonne et qu'elle m'accompanera aussi longtemps voire plus

lundi 27 octobre 2008

Musique : Erik Mongrain

Petite vidéo d'un mutant :



Ca s'appel le "AirTap", ça change du "Air Guitare" qui sert à rien ...

vendredi 24 octobre 2008

Informatique : Android devient OpenSource !

Il fallait s'y attendre, Google ne cesse de s'étendre et après avoir touché la publicité via Google Adsense, c'est maintenant les mobiles.
Cela n'est pas nouveau pour ceux qui suivent l'actualité informatique mais pour toucher ce marché, Google a créé sa propre plateforme incluant un système d'exploitation, des outils, logiciels, ihm et tout ce qui va avec sous l'appellation de Google Android.
Quelques mois apres la disponibilité de mobiles fonctionnant sous cet OS, Google a tout simplement ouvert le code source : tout y est, rien est caché, du bootloader (bootstrap plutôt) à l'API de haut niveau pour les développeurs ne désirant que proposer leur logiciels sur cet environnement.
Compter un téléchargement d'environ 2.1 GO, de 6 GO d'espace libre, de patience pour compiler le tout et en route pour vos modifications !
Ca change d'Apple donc profitez en :)




Lien : Code Source Google Android

jeudi 23 octobre 2008

Emulation : AmiKit

Les plus jeunes d'entre vous ne connaissent pas cette machine mais le simple fait d'évoquer son nom, l'Amiga, fera tendre les oreilles vers l'avant des geeks barbus trentenaires et plus.
Si j'en parle, ce n'est pas pour vous proposer un enième émulateur de la bête, WinUAE étant LA référence, non c'est pour vous parler d'AmiKit.
En effet, disposer d'un environnement Amiga émulé n'est pas ce qu'il y a de plus façile à mettre en oeuvre pour le néophyte, c'est pour cela que de nombreux bénévoles mettent à disposition des packs prêts à l'emploi pour disposer de tout ce qu'il faut pour revivre une experience unique, AmiKit est de ceux la.
Celui ci est tellement bien fait qu'il supplante allegrement tous ce que j'ai pu tester, il dispose d'office d'une image disque remplis d'applications, à jour qui plus est ainsi que de tout ce qu'un système d'exploitation doit avoir (navigateur internet, lecteur audio, vidéo, client irc, jeux, outils de programmation, démos cultes, modules cultes, outils de paramètrages tres nombreux et complets ...).
Sachez néanmoins que ce système impose d'avoir à disposition les disquettes ROM (KickStart 3.x et > ) ainsi que le CD d'installation d'OS 3.9.
Ce qui peut paraitre comme une contrainte n'en est pas une et permet aux personnes désireuses de s'y mettre de le faire en supportant ceux qui essaient de maintenir la flamme.
A ce titre, je vous invite à faire un tour chez Amiga Forever qui vend aussi son propre environnement mais la, le CD d'Amiga Forever 2008 pourra être utilisé par AmiKit lors de l'installation de celui ci, testé et approuvé par votre serviteur :)

samedi 4 octobre 2008

Jeux Vidéos : Nintendo DSi

Nintendo vient d'annoncer sa nouvelle console portable : la DSi. Voila, c'est fait, rien d'autre à ajouter.
Bon, je vais tenter de trouver des nouveautés :

- un peu plus fine,
- deux super capteurs vidéo de, tenez vous bien, 3 mégapixels ! Divisez le par 10 et vous avez le compte,
- un écran nettement plus grand, c'est simple, il passe d'un vulgaire 3 petits pouces à un gigantesque 3.25 pouces !
- un son de meilleur qualité dixit Nintendo (j'en doute),
- un slot pour carte SD (enfin une vraie nouveauté),
- navigateur internet, dictaphone, lecteur mp3,
- service DSi Shop pour dépenser les sous pour des jeux à télécharger qui vont surement annoncer une nouvelle ère dans le jeux vidéo (amateurs de jeux sur mobile, ayez peur !),
- succrage du port GBA.







Sortie le 01 novembre au pays des suchis pour 129 € et plus tard, tablez sur le printemps 2009 en Europe à pas 129 € mais surement dans les 179 €, enfilage inside.

J'ai hâte d'en apprendre plus sur la nouvelle Wii.

dimanche 28 septembre 2008

Chronique musicale : Wendy Carlos

Yopla :)
Histoire de changer, je me suis dit : et si je partageais avec vous les musiciens que j'apprécie ?
Etant plutôt hors circuit commercial, bon nombre d'entre eux ne vous diront absolument rien et pourtant ils sont souvent pionnier dans leur domaine et mériteraient beaucoup plus de considération.



Pour débuter, j'ai choisis Wendy Carlos : plus qu'une auteur/compositrice, elle aura marqué de sa pate le monde de la musique.
En effet, elle fut très tôt passionnée par ces machines : les synthétiseurs.
Prenant la place d'une chambre de 20m², ces engins la fascinait à tel point qu'elle entrepris ses propres recherches pour créer de nouveaux sons et même de nouvelles machines, aidée par des études en musique et en sciences passés à l'université de Brown.
Grâce à l'aide de Rachel Elkind, sa productrice, elle réussit à sortir son premier album avec ce titre :



Il faut savoir que nous ne sommes qu'en 1968 ! La force de cette musique (ce n'est pas l'original, pas envie d'être poursuivi ^_^ ) est d'avoir marié une musique que tout le monde connait avec des sons que personne n'a jamais entendu.
Wendy Carlos l'explique très bien car proposer des sons agressifs, "alien" n'aurait pas eu l'effet escompté.
Toujours à la pointe, elle avait déjà commencé à mixer 2 pistes stéréo avant tout le monde : c'est ce qu'on a appelé par la suite le Dolby Surround.
Sort l'année qui suit, l'album "The Well-Tempered Synthesizer", entièrement créé sur un synthétiseur Moog, qu'elle a d'ailleur aidé à fabriquer en ajoutant sa touche perso à çe magnifique synthé : le Moog Modular.



En 1972, "Sonic Seasonings" sort : il s'agit d'un double vinyle longue durée. Et pour cause ! Il s'agissait d'un projet experimental ayant pour objectif de représenter les 4 saisons, il y avait donc une et seule musique par façe, celle-ci étant une saison en particulier.
Ces musiques longues, calmes, limite hypnotique étaient encore quelque chose que personne n'avait jamais entendu : elle venait de créer un nouveau genre, l'ambiant.
Mais c'est surtout un an plus tôt que Wendy Carlos montra enfin tout son génie : c'est elle qui à créé la musique d'Orange Mécanique :



La encore, de la musique classique avec une qualité au niveau de la synthèse sonore encore améliorée mais surtout l'utilisation, pour la première fois, d'un vocoder ! (nous ne sommes qu'en 1971, ne l'oubliez pas)

En 1982, sort le film culte Tron dont elle fera la bande originale, rien que ça.
Je me répete mais encore une fois, en tant que précurseur, c'est la première fois que nous entendons des sons analogiques ET numériques!

Digital Moonscape sort en 1984, album 100% numériques et très planant.

Elle fera la BO du film "La belle et la bête" sortis en 1986 où elle utilisa la technique de l'intonation juste.

En 1987, elle sort "Secrets of Synthesis", une lecture de ses travaux où elle explique ce qu'elle fait et comment elle le fait.

Depuis 1998, ses compositions ont été remasterisés en haut qualité (20 bits) et sont toujours disponibles sur son site.

Vous l'aurez compris, Jean Michel Jarre semble n'avoir rien inventé à la lecture des compositions de Wendy Carlos, ce sont des gens comme elle et Robert Moog (décédé dans l'anonymat en Françe) que la musique avance réellement.

Outre son talent d'auteur/compositrice, elle a d'autres passions comme le dessin/peinture, les éclipses totales de soleil ou encore d'autres domaines experimentaux.

Il y a un dernier détail la concernant mais cela n'a aucun interêt d'en parler et n'enleve en rien tout le respect qu'elle mérite.

dimanche 21 septembre 2008

Insolite : Veejing

Vu sur PC Inpact, ce vidéo montage qui peut être assimilé a du veejing (vidéo dj'ing), ça démarre lentement mais une fois qu'on a compris le principe, on reste bouche bée par tant de créativité.

lundi 8 septembre 2008

Humour : Hello Geekette

Un petit site que j'invite tout le monde à visiter pour qui veut passer un agréable moment en visionnant la vie trépidante d'une geekette vivant avec un colocataire aussi geek que peut l'être François Bayrou :D
C'est assez bien fait, original, marrant et le jeux des acteurs est crédible, ça sent le vécu :p
Bon, être geek est aussi un plus car les références sont nombreuses.
Bon visionnage.

vendredi 22 août 2008

Musique : Ma playlist

Un petit billet pour vous faire partager ma playlist, en esperant qu'elle vous plaira :)

mardi 12 août 2008

Informatique : NVidia PhysX Pack

Amis geek(ette) de tout poil(ou pas), NVidia, toujours dans un soucis de service (marketing) nous propose un pack ainsi que des pilotes pour les GeForce 8/9 tirant partis de l'accélération physique matériel.
Pour ce faire, ce pack est censé montré tout le potentiel de leurs GPU pour mener à bien ce support matériel via un pack de carte pour UT 3, des démos technologique et même un FPS complet !
Bon, en même temps, cela est disponible depuis un moment mais pas ces derniers pilotes qui sont basés sur la dernière version des pilotes PhysX.
Force est de constater que les gains sont réels sans impacter les frames par secondes, CUDA (API GPGPU) prouve une fois de plus sa maturité la où AMD propose une API un peu plus disparate et une documentation loin de la qualité de NVidia.
Bref, ça vaut le coup d'essayer :)

Lien : NVidia PhysX Pack

High-Tech : tous des Casper ?

Je l'espère !
En tout cas, des scientifiques un peu fou (cliché un peu façile ...) sont sur une avancée technologique qui permettrait de renvoyer les rayons lumineux et ainsi de rendre invisible ledit objet.
Nous sommes encore loin de la cap de Harry Potter notamment à cause de contraintes budgétaires (le coût de la technologie permettant de produire un objet de la taille d'une pomme réfléchissante couterais des dixaines de millions de $) mais les scientifiques sont très confiant et pensent que dans une bonne dizaine d'année, cela serait faisable.
Les filles n'ont qu'à bien se tenir :o

Source : Clubic

mercredi 6 août 2008

Société : STUFF

Une petit lien qui prête à réfléchir.
Sans commentaire :)

dimanche 3 août 2008

Programmation : Windows SDK 2008

Bon, certains d'entre vous le savent déjà mais pour tous les autres, le SDK nouveau est disponible, il permet de tirer parti des dernières technologies (.NET 3.5 et Win32) pour développer sa killer app :)
Ca ne fait "que" 6 mois que c'est disponible mais bon, je roule en Java/PureBasic depuis, c'est juste que j'avais besoin de compiler une application qui en dépend (Open ModPlug Tracker) :D

Liens :

lundi 14 juillet 2008

Celt : codec ultime ?

Kezako le CELT ?
Il s'agit d'un nouveau codec audio. Bon jusque la, rien de bien nouveau sous le soleil mais j'ai écouté les échantillons proposés sur le site et ma foi, ça sonne plus que bien !
C'était un test subjectif mais les tests plus techniques ne font que corroborer mon ressentis.
Il explique tres bien sur son blog les fondamentaux de ses algorithmes, il est lui même étonné du résultat qui sont très encouragent surtout quand on voit la latence.
Bref, un codec à suivre de près.