Byte Twiddling: Optimizando el manejo de (muuuuchos) bytes
La manera más obvia de manipular secuencias de bytes en Python casi nunca es la que procesa los datos de la forma más rápida. Para evitar caer en la pérdida de tiempo de programador que supone codificar un módulo en C, presentaremos en esta charla algunas de las técnicas que permiten operar de forma óptima sobre secuencias de bytes (que representan imágenes, sonidos y coordenadas), tanto de la biblioteca standard de Python como de algunas extensiones comunes como son NumPy, Imaging y PyOpenGL.
bytes, bytes, bytes
valores2 = []
for v in valores:
valores2.append( operacion(v) )
# list comprehension [ operacion(v) for v in valores ] # retro map(operacion, valores) # generador ( operacion(v) for v in valores )
Uds dicen: "Ah, ya sé, Usaré C..." (o pyrex o alguna otra cosa) Yo digo: "Momento! Ya debe haber algo hecho!"
import moduloloco moduloloco.operacionsobrebytes(bytes)
Caso 1: Optimizando tinysynth
- alocado alocador
- un juego en solamente 64kb de código
- sin archivos de imágenes
- sin archivos de sonidos
http://python.org.ar/pyar/Proyectos/AlocadoAlocador
tinysynth
(gráfico)
- generador de notas
- secuenciador de partitura
tipos de datos: sample width y sample rate
http://en.wikipedia.org/wiki/File:Signal_Sampling.png
- sample rate (frecuencia)
- sample width
- número de canales (mono, stereo, 5.1)
Por ejemplo: 44.1 khz, 16bits, 2 canales
stdlib: wave
http://docs.python.org/library/wave.html
stdlib: audioop
http://docs.python.org/library/audioop.html
- volmin, volmax = audioop.minmax(fragment, width)
- potencia = audioop.rms(fragment, width)
PyGame: arrays
- pygame.surfarray
- pygame.sndarray
- pygame.sndarray.make_sound
Un poco de teoría
tipos de datos
http://en.wikipedia.org/wiki/Primitive_data_type
Enteros:
| Tamaño | Nombres Assembler y C | Rango con signo | Rango sin signo |
| 8 bits | Byte, char | −128 a +127 | 0 a 255 |
| 16 bits | Word, short int | −32,768 a +32,767 | 0 a 65,535 |
| 32 bits | Double Word, long int | −2,147,483,648 a +2,147,483,647 | 0 a 4,294,967,295 |
| 64 bits | Quad Word, long long | −9,223,372,036,854,775,808 a +9,223,372,036,854,775,807 | 0 a 18,446,744,073,709,551,615 |
De punto flotante:
| Tamaño | Nombre en C | Rango |
| 32 bits | float | 3.4e-038..3.4e+038 |
| 64 bits | double float | 1.7e-308..1.7e+308 |
http://en.wikipedia.org/wiki/Floating-point
endianness
http://en.wikipedia.org/wiki/Endianness
- little endian (intel, amd)
- big endian (motorola, powerpc, sparc)
stdlib: struct.Struct(format)
http://docs.python.org/library/struct.html
De bytes a lista y vicerveza
- hex editor -> mc
- format: cbBhHiIllqQfdsp
- <> little big endian
- pack, unpack, format
- struct.pack(fmt, v1, v2, ...)
- lista = struct.unpack(fmt, string)
- longitud = struct.calcsize(fmt)
struct format
| Format | C Type | Python |
| x | pad byte | sin valor |
| c | char | string de largo uno |
| b | signed char | integer |
| B | unsigned char | integer |
| ? | _Bool | bool |
| h | short | integer |
| H | unsigned short | integer |
| i | int | integer |
| I | unsigned int | integer o long |
| l | long | integer |
| L | unsigned long | long |
| q | long long | long |
| Q | unsigned long long | long |
| f | float | float |
| d | double | float |
| s | char[] | string |
| p | char[] | string |
| P | void * | long |
Caso 2: Bustrofedón
Yaco hace la oveja eléctrica
oveja eléctrica es un proyecto en curso cuyo objetivo es crear un compositor artificial: un sistema que, mediante procesos existentes en una o más computadoras, sea capaz de crear música de manera intencional, no aleatoria e independiente de toda influencia humana. oveja eléctrica recibió el primer premio en la categoría proyecto multidisciplinario experimental (premio limb0 2003) del museo de arte moderno de buenos aires.
http://blog.yaco.net/oveja-electrica/
(más imágenes en http://yaco.net/oe/colabs-es.php )
Pregunta a la lista: Bustrofedón
generar un sonido extraño en base a una imagen
Sin optimizar: http://proposicion.org.ar/lurker/message/20060630.025730.511174d6.es.html
- lee los pixels una imagen RGB, transformándolos en valores de gris de 16 bits
- los reordena en bustrofedón espejado
- los escribe como frames mono en un archivo de audio de sample rate rarito.
stdlib: array
http://docs.python.org/library/array.html
- (+) es parte de stdlib
- (+) eficiente en espacio usado
- (-) no hay operaciones eficientes
numpy
- (-) módulo aparte: apt-get install python-numpy
- (+) eficiente en espacio
- (+) Muuuuchas operaciones
Python Imaging Library
- módulo aparte: apt-get install python-imaging
- raster images (rectángulos de pixels)
tipos de datos: Bits per pixel
http://www.pythonware.com/library/pil/handbook/concepts.htm
- 1 (1-bit pixels, black and white, stored with one pixel per byte)
- L (8-bit pixels, black and white)
- P (8-bit pixels, mapped to any other mode using a colour palette)
- RGB (3x8-bit pixels, true colour)
- RGBA (4x8-bit pixels, true colour with transparency mask)
- I (32-bit signed integer pixels)
- F (32-bit floating point pixels)
Bustrofedón optimizado
http://proposicion.org.ar/lurker/message/20060630.191648.4f4294aa.es.html
Caso 3: Partículas con numpy
OpenGL
display lists
- glNewList(id, GL_COMPILE)
- glEndList()
- glCallList(id)
vertex arrays
- glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
- glEnableClientState(GL_VERTEX_ARRAY)
- glEnable(GL_TEXTURE_COORD_ARRAY)
- glEnable(GL_COLOR_ARRAY)
- glVertexPointer
- glTexCoordPointer
- glColorPointer
- glDrawArrays
- glPopClientAttrib()
tipos de datos
- vertices: arrays de floats (x,y,z)
- colores: arrays de floats (r,g,b,a)
- coord. de texturas: arrays de floats (u, v)
Conclusion
valores2 = []
for v in valores:
valores2.append( operacion(v) )
import moduloloco moduloloco.operacionsobrebytes(bytes)
![(please configure the [header_logo] section in trac.ini)](/charlas-alecu/chrome/site/your_project_logo.png)
