NewHeadline
@file setup.py
@file speex.pyx
cdef externs
string.h
stdio.h
stdlib.h
math.h
Python.h
speex.h
cdef class new
c attribs
__init__
__dealloc__
encode
decode
import sys
from distutils.core import setup, Extension
from Pyrex.Distutils import build_ext
incDirs = ['../libspeex']
libs = []
libDirs = []
runtimeLibDirs = []
cMacros = []
#extraLinkArgs = ['-g', '/usr/lib/libspeex.a'] # static
extraLinkArgs = ['-g', '-lspeex'] # shared
if sys.platform == 'win32':
libDirs.append('..\\win32\\Release')
libs = []
extraLinkArgs = ['..\\win32\\libspeex\\Release\\libspeex.lib']
speexmodule = Extension('speex',
['speex.pyx'],
define_macros=cMacros,
include_dirs=incDirs,
libraries=libs,
library_dirs=libDirs,
runtime_library_dirs=runtimeLibDirs,
extra_compile_args=['-g'],
extra_link_args=extraLinkArgs
)
setup(name = 'speex',
version = '1.0',
description = 'Python interface to the Speex audio codec',
ext_modules = [speexmodule],
cmdclass = {'build_ext': build_ext},
)
@language python
"""
speex.pyx
Python wrapper for Speex speech codec (www.speex.org)
Defines a 'speex' object through which encoding and
decoding of audio data can be performed.
"""
version = "0.2"
try:
x = True
except:
True = 1
False = 0
@others
# basic system and python facilities
@others
cdef extern from "string.h":
cdef void *memset(void *s, int c, int n)
cdef void *memcpy(void *dest, void *src, int n)
cdef extern from "stdio.h":
int printf(char *format,...)
cdef extern from "stdlib.h":
void *malloc(int size)
void *realloc(void *ptr, int size)
void free(void *ptr)
cdef extern from "math.h":
double fabs(double x)
# Python-specifics
cdef extern from "Python.h":
object PyString_FromStringAndSize(char *, int)
# Speex-specifics
cdef extern from "speex.h":
ctypedef struct SpeexBits:
char *bytes # "raw" data
int nbBits # Total number of bits stored in the stream
int bytePtr # Position of the byte "cursor"
int bitPtr # Position of the bit "cursor" within the current byte
int owner # Does the struct "own" the "raw" buffer (member "bytes")
int overflow # Set to one if we try to read past the valid data
int buf_size # Allocated size for buffer
ctypedef struct SpeexMode:
void *mode
cdef enum SPEEX_SYMBOLS:
SPEEX_SET_QUALITY
SPEEX_GET_FRAME_SIZE
SPEEX_SET_ENH
SPEEX_GET_ENH
cdef SpeexMode speex_nb_mode
cdef void speex_bits_init(SpeexBits *bits)
cdef void speex_bits_read_from(SpeexBits *bits, char *bytes, int len)
cdef int speex_bits_write(SpeexBits *bits, char *bytes, int max_len)
cdef void speex_bits_reset(SpeexBits *bits)
cdef void speex_bits_destroy(SpeexBits *bits)
cdef void *speex_encoder_init(SpeexMode *mode)
cdef int speex_encoder_ctl(void *state,
int request,
void *ptr)
cdef int speex_encode(void *state, float *inbuf, SpeexBits *bits)
cdef void speex_encoder_destroy(void *state)
cdef void *speex_decoder_init(SpeexMode *mode)
int speex_decoder_ctl(void *state, int request, void *ptr)
cdef int speex_decode(void *state,
SpeexBits *bits,
float *out)
cdef void speex_decoder_destroy(void *state)
cdef class new:
@others
cdef void *encState
cdef int encQuality
cdef int encFramesPerBlock
cdef float *encBuf
cdef float *encPtr
cdef int encNumFrames
cdef SpeexBits encBits
cdef int raw
# Data for decoding
cdef void *decState
cdef int decQuality
cdef unsigned char *decBuf
cdef unsigned char *decPtr
cdef unsigned short decBlkSize
cdef int decNumBytes
cdef int decPhase
cdef int decEnhanceOn
cdef SpeexBits decBits
cdef public object debug
cdef public object endianness
def __init__(self, quality=8, raw=0, **kw):
"""
Create a new speex speech stream object
Arguments:
- quality - 0 (lowest) to 10 (highest), default 8
- raw - set to 1 for encoding from and decoding to string, default 0
Keywords:
- debug - set to 1 to issue debug messages, default 0
The created speex stream object has two methods:
- encode - encode a block of speech audio data
Arguments:
- block of audio data, as sequence of frames, where
each frame is an int
Returns:
- raw string containing encoded data, or
empty string if there is not yet any encoded
data available
- decode - decodes a block of speech audio data
Arguments:
- block of encoded data, as raw string,
Returns:
- block of audio data, as sequence of ints, or
an empty sequence if there is no decoded data
available yet
Notes:
- Both of these methods use internal buffering, which means that
you can feed in data piecemeal. This helps a lot when sending and
receiving data over the net.
"""
cdef int is_raw
#cdef SpeexMode speex_nb_mode
# Set up encoder
self.encState = speex_encoder_init(&speex_nb_mode)
self.encQuality = quality
is_raw = raw
self.raw = is_raw
self.debug = int(kw.get('debug', 0))
speex_encoder_ctl(self.encState, SPEEX_SET_QUALITY, &self.encQuality)
#printf("speex1: using new pyrex wrapper, quality=%d\n", self.encQuality)
speex_encoder_ctl(self.encState, SPEEX_GET_FRAME_SIZE, &self.encFramesPerBlock)
#printf("encoder frame size=%d\n", self.encFramesPerBlock)
self.encBuf = <float *>malloc(self.encFramesPerBlock * sizeof(float))
if not self.encBuf:
raise Exception("Out of memory")
memset(self.encBuf, 0, self.encFramesPerBlock * sizeof(float))
self.encNumFrames = 0
self.encPtr = self.encBuf
speex_bits_init(&self.encBits)
# Set up decoder
self.decState = speex_decoder_init(&speex_nb_mode)
self.decEnhanceOn = 1
speex_decoder_ctl(self.decState, SPEEX_SET_ENH, &self.decEnhanceOn)
self.decBuf = <unsigned char *>malloc(2) # just big enough for leading length field
self.decPhase = 0
if not self.decBuf:
raise Exception("Out of memory")
self.decPtr = self.decBuf
self.decNumBytes = 0
speex_bits_init(&self.decBits)
def __dealloc__(self):
# Destroy the encoder state and data
speex_encoder_destroy(self.encState)
if self.encBuf:
free(self.encBuf)
# Destroy the decoder state
speex_decoder_destroy(self.decState)
if self.decBuf:
free(self.decBuf)
# Destroy the bit-packing structs
speex_bits_destroy(&self.encBits)
speex_bits_destroy(&self.decBits)
def encode(self, input, raw=None):
"""
Encode some audio data
Arguments:
- data - sequence of audio frames to encode, OR string of 16-bit frames
- raw - true if data being passed in is a string of 16-bit frames
defaults to whatever raw arg was passed to constructor
Returns:
- raw string with encoded data
"""
cdef int numInputFrames
cdef float *framesBuf, *framesPtr
# cdef float thisframe
cdef int i
cdef int totFrames
# cdef SpeexBits bits;
cdef int cbitsSiz
# cdef int cbitsSiz = 2048
# cdef char cbits[cbitsSiz]
cdef char cbits[2048]
cdef int nBlocks
cdef int nBytes
cdef char *bufOut
cdef int bufOutSiz
cdef int remainder
cdef char *rawbuf
cdef short *frameptr
cbitsSiz = self.encFramesPerBlock * 5 / 4
bufOut = <char *>malloc(0)
bufOutSiz = 0
inputFramesList = []
#printf("encode: ok1\n")
# override raw flag if user has passed in a string
if raw is None:
raw = self.raw
if type(input) is type(""):
raw = 1
# Determine number of frames
if raw:
numInputFrames = len(input) / 2 # hardwired 16-bit frames
else:
numInputFrames = len(input)
#printf("encode: ok2\n")
# printf("enc - numInputFrames = %d\n", numInputFrames)
if numInputFrames == 0:
return ''
#printf("encode: ok3\n")
# Encode what we have, block by block
totFrames = numInputFrames + self.encNumFrames
#printf("totFrames=%d, input data size=%d\n",
# totFrames, totFrames * sizeof(short))
framesBuf = <float *>malloc(totFrames * sizeof(float))
framesPtr = framesBuf
if not framesBuf:
raise Exception("Out of memory")
#printf("encode: ok4\n")
# Copy in the fragments we have in buffer
# printf("copying in buf of %d frames\n", self.encNumFrames)
for i from 0 <= i < self.encNumFrames:
framesPtr[i] = self.encBuf[i]
#printf("encode: ok4a = i=%d, self.encNumFrames=%d\n",
# i, self.encNumFrames)
framesPtr = framesPtr + i
#printf("encode: ok5\n")
# Extract the rest from input sequence, depending on whether input is str or list
# printf("copying extra %d frames from input\n", numInputFrames);
if raw:
rawbuf = input
frameptr = <short *>rawbuf
for i from 0 <= i < numInputFrames:
# assume little-endian - sorry, mac hackers
# frame = rawptr[0] + 256 * rawptr[1]
# rawptr += 2
# *framesPtr++ = (float)frame
framesPtr[i] = frameptr[i]
framesPtr = framesPtr + i
frameptr = frameptr + i
# thisframe = *frameptr++
# if (i < 10)
# {
# printf("encode: thisframe=%f\n", thisframe)
# }
# *framesPtr++ = thisframe
else:
for i from 0 <= i < numInputFrames:
framesPtr[i] = input[i]
framesPtr = framesPtr + i
# thisframe = PyInt_AsLong(PyList_GetItem(input, i))
# if (i < 10)
# {
# printf("encode: thisframe=%f\n", thisframe)
# }
# *framesPtr++ = thisframe
#printf("written %d frames to buf\n", framesPtr - framesBuf)
#printf("encode: ok6\n")
# Encode these frames
nBlocks = totFrames / self.encFramesPerBlock
framesPtr = framesBuf
for i from 0 <= i < nBlocks:
# printf("seeking to encode a block, nBlocks=%d\n", nBlocks)
speex_bits_reset(&self.encBits)
# printf("ok1 - state=0x%lx, buf=0x%lx, bits=0x%lx\n",
# self.encState, framesBuf, &self.encBits)
speex_encode(self.encState, framesPtr, &self.encBits)
# printf("ok2\n")
nBytes = speex_bits_write(&self.encBits, cbits, cbitsSiz)
#printf("nBytes=%d\n", nBytes)
bufOut = <char *>realloc(bufOut, bufOutSiz+nBytes+2)
# printf("ok4\n")
# write out 2 length bytes
bufOut[bufOutSiz] = nBytes % 256
bufOut[bufOutSiz+1] = nBytes / 256
bufOutSiz = bufOutSiz + 2
memcpy(bufOut+bufOutSiz, cbits, nBytes)
# printf("ok5\n")
bufOutSiz = bufOutSiz + nBytes
# printf("ok6\n")
framesPtr = framesPtr + self.encFramesPerBlock
#printf("encode: ok7\n")
# stick remainder, if any, into buffer
self.encNumFrames = totFrames - (nBlocks * self.encFramesPerBlock)
remainder = self.encNumFrames * sizeof(float)
memcpy(self.encBuf, framesPtr, remainder)
# memset(self.encBuf, 0, self.encFramesPerBlock * sizeof(float))
# printf("encNumFrames=%d\n", self.encNumFrames)
# printf("remainder=%d\n", remainder)
#printf("encode: ok8\n")
# ditch temp buffer
free(framesBuf)
#printf("encode: ok9\n")
# pass back encoded buffer as raw string
#printf("bufOutSize=%d\n", bufOutSiz)
return PyString_FromStringAndSize(bufOut, bufOutSiz)
def decode(self, input, raw=None):
"""
Decode an encoded block, return as sequence of frame tuples
Arguments:
- encoded - raw string, containing encoded data
- raw - True if data is to be returned as string of 16-bit frames, defaults to
whatever raw value was passed to constructor
Returns:
- decoded blocks, as sequence of frames, where each frame
or a string of these 16-bit frames if raw is True
is an int
"""
cdef unsigned char *encBuf
cdef unsigned char *encBufEnd
cdef unsigned char *encPtr
cdef int encBufLen
cdef int numDecFrames # number of decoded frames
# cdef int cbitsSiz
# cdef char cbits[cbitsSiz]
cdef float *decFloats
cdef float *decFloats1
cdef short *decShorts
cdef short *decShorts1
cdef int decBlocks
cdef int i
cdef int is_raw
cdef int needed
cdef int newNumFrames
cdef char *tmp
#printf("decode: ok1\n")
tmp = input
encBuf = <unsigned char *>tmp
encBufEnd = NULL
encPtr = NULL
encBufLen = 0
decFloats = <float *>malloc(0)
decShorts = <short *>malloc(0)
decBlocks = 0
if raw is None:
raw = self.raw
is_raw = raw
#printf("decode: ok2, raw=%d\n", is_raw)
# We get an earlymark if caller provided no data
encBufLen = len(input)
if encBufLen == 0:
if is_raw:
return ''
else:
return []
#printf("decode: ok3\n")
# decode the sucker
encPtr = encBuf
encBufEnd = encBuf + encBufLen
#printf("decode: ok4, len=%d\n", encBufLen)
while encPtr < encBufEnd:
# state depends on whether we've received the block header count bytes
if self.decPhase == 0:
# Grab LSB of block size
self.decBuf[0] = encPtr[0]
#printf("decode: ok4a - LSB=%02x\n", encPtr[0])
self.decPhase = 1
encPtr = encPtr + 1
encBufLen = encBufLen - 1
continue
elif self.decPhase == 1:
# Grab MSB of block size and determine total block size
self.decBuf[1] = encPtr[0]
#printf("decode: ok4b - LSB=%02x\n", encPtr[0])
self.decBlkSize = self.decBuf[0] + 256 * self.decBuf[1]
# resize dec buffer to suit
# todo - find better way to sanity check the size
self.decBuf = <unsigned char *>realloc(
<void *>self.decBuf,
self.decBlkSize)
self.decPtr = self.decBuf
self.decNumBytes = 0
self.decPhase = 2
encPtr = encPtr + 1
encBufLen = encBufLen - 1
continue
else:
#printf("decode: ok4c siz=%d decnumbytes=%d\n",
# self.decBlkSize, self.decNumBytes)
needed = self.decBlkSize - self.decNumBytes
#printf("decode: ok4d encBufLen=%d needed=%d\n",
# encBufLen, needed)
# do we have enough input data to complete a frame?
if encBufLen >= needed:
newNumFrames = (decBlocks + 1) * self.encFramesPerBlock
# great - decode frame and add to our array of shorts
memcpy(self.decPtr,
encPtr,
self.decBlkSize - self.decNumBytes)
encPtr = encPtr + needed
encBufLen = encBufLen - needed
# do the decoding
# expand shorts and floats buffers
decShorts = <short *>realloc(decShorts, newNumFrames * sizeof(short))
decShorts1 = decShorts + decBlocks * self.encFramesPerBlock
decFloats = <float *>realloc(decFloats, newNumFrames * sizeof(float))
decFloats1 = decFloats + decBlocks * self.encFramesPerBlock
# Copy the data into the bit-stream struct
speex_bits_read_from(&self.decBits, <char *>self.decPtr, self.decBlkSize)
# Decode the data
speex_decode(self.decState, &self.decBits, decFloats1)
# Copy from float to short (16 bits) for output
for i from 0 <= i < self.encFramesPerBlock:
decShorts1[i] = decFloats1[i]
self.decPhase = 0 # back to awaiting LSB of count header
self.decNumBytes = 0
if self.debug:
printf("self.decBuf=%lx\n", self.decBuf)
self.decBuf = <unsigned char *>realloc(self.decBuf, 2)
decBlocks = decBlocks + 1
continue
else:
#printf("decode: ok4e\n")
# not enough to decode another speex frame - just stick into buffer
if self.debug:
printf("decPtr=%lx, encPtr=%lx, encBufLen=%d\n",
self.decPtr, encPtr, encBufLen)
memcpy(self.decPtr, encPtr, encBufLen)
self.decPtr = self.decPtr + encBufLen
encBufLen = 0
break
#printf("decode: ok5\n")
# did we get anything?
if decBlocks > 0:
numDecFrames = decBlocks * self.encFramesPerBlock
if is_raw:
ret = PyString_FromStringAndSize(<char *>decShorts, numDecFrames * 2)
else:
# build up a sequence of tuples
ret = []
for i in range(numDecFrames):
ret.append(decShorts[i])
else:
if is_raw:
ret = ""
else:
ret = []
#printf("decode: ok6\n")
free(decShorts)
free(decFloats)
return ret
# return Py_BuildValue("s#", decBuf, decBufLen)