diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..14b491b --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +"""Setup for rpitx.""" + +from setuptools import setup, Extension + +setup( + name='rpitx', + version='0.1', + description='Raspyberry Pi radio transmitter', + author='Brandon Skari', + author_email='brandon@skari.org', + url='https://github.com/F5OEO/rpitx', + ext_modules=[ + Extension( + '_rpitx', + [ + 'src/python/_rpitxmodule.c', + 'src/RpiTx.c', + 'src/mailbox.c', + 'src/RpiDma.c', + 'src/RpiGpio.c', + ], + extra_link_args=['-lrt'], + ), + ], + package_dir={'': 'src/python'}, + install_requires=['wave', 'pydub'], +) diff --git a/src/RpiTx.c b/src/RpiTx.c index 0c63b6a..b2b66c8 100644 --- a/src/RpiTx.c +++ b/src/RpiTx.c @@ -108,7 +108,6 @@ uint32_t GlobalTabPwmFrequency[50]; char EndOfApp=0; unsigned char loop_mode_flag=0; char *FileName = 0; -void *rawFileMemory = NULL; int FileInHandle; //Handle in Transport Stream File static void udelay(int us) @@ -1203,7 +1202,7 @@ int pitx_run( { IQArray=malloc(DmaSampleBurstSize*2*sizeof(signed short)); // TODO A FREE AT THE END OF SOFTWARE char dummyheader[HEADER_SIZE]; - if (read(FileInHandle,dummyheader,HEADER_SIZE) != HEADER_SIZE) { + if (readWrapper(dummyheader,HEADER_SIZE) != HEADER_SIZE) { fatal("Unable to read header\n"); } diff --git a/src/python/__init__.py b/src/python/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/python/_rpitxmodule.c b/src/python/_rpitxmodule.c new file mode 100644 index 0000000..b4b22e2 --- /dev/null +++ b/src/python/_rpitxmodule.c @@ -0,0 +1,30 @@ +#include +#include "../RpiTx.h" +#include "../RpiGpio.h" + + +static PyObject* +_rpitx_broadcast(PyObject* self, PyObject* args) { + int address; + int length; + float frequency; + if (!PyArg_ParseTuple(args, "iif", &address, &length, &frequency)) { + return NULL; + } + + setUpReadArray((void*)address, length); + pitx_run(MODE_IQ, 44000, frequency, 0.0, 0, readArray, NULL); + Py_RETURN_NONE; +} + + +static PyMethodDef _rpitx_methods[] = { + {"broadcast", _rpitx_broadcast, METH_VARARGS, "Low-level broadcasting."}, + {NULL, NULL, 0, NULL} +}; + + +PyMODINIT_FUNC +init_rpitx(void) { + (void) Py_InitModule("_rpitx", _rpitx_methods); +} diff --git a/src/python/rpitx.py b/src/python/rpitx.py new file mode 100644 index 0000000..e03dcde --- /dev/null +++ b/src/python/rpitx.py @@ -0,0 +1,56 @@ +"""Python interface to rpitx.""" + +from pydub import AudioSegment +import StringIO +import array +import _rpitx +import wave + + +def play_fm(file_, frequency): + """Play a music file over FM.""" + + def _reencode(file_name): + """Returns a file-like object reencoded to the proper WAV format.""" + reencoded = StringIO.StringIO() + # AudioSegment doesn't support context managers either + original = AudioSegment.from_file(file_name) + if original.channels > 2: + raise ValueError('Too many channels in sound file') + if original.channels == 2: + # TODO: Support stereo. For now, just overlay into mono. + left, right = original.split_to_mono() + original = left.overlay(right) + + original.export(reencoded, format='wav', bitrate='44k') + return reencoded + + encoded_file = None + if isinstance(file_, str): + if file_.endswith('.wav'): + with open(file_) as raw_file: + # wave.open doesn't support context managers, so we need to be + # careful about closing the file + wav_file = wave.open(raw_file, 'r') + num_channels = wav_file.getnchannels() + framerate = wav_file.getframerate() + sample_width = wav_file.getsampwidth() + wav_file.close() + + if ( + num_channels != 1 + or framerate != 1 + or sample_width != 2 + ): + encoded_file = _reencode(file_) + else: + encoded_file = AudioSegment.from_file(file_) + else: + encoded_file = _reencode(file_) + else: + encoded_file = _reencode(file_) + + raw_array = array.array('c') + raw_array.fromstring(str(encoded_file)) + array_address, length = raw_array.buffer_info() + _rpitx.broadcast(array_address, length, frequency)