Skip to content

Commit

Permalink
Merge pull request #28 from joextodd/v2.0.0
Browse files Browse the repository at this point in the history
v1.1.0
  • Loading branch information
joextodd committed Mar 11, 2019
2 parents 87b8659 + 305430b commit 9702ff1
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 40 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -4,6 +4,7 @@ language: python
python:
- "2.7"
- "3.6"
- "3.7"
install:
- pip install coveralls
before_script:
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.rst
@@ -0,0 +1,13 @@
Changelog
----------

**v1.1.0**

* Add support for libsoundio v2.0.0
* Add support for Windows (thanks @cameronmaske)
* Fix for malloc errors
* Fix typos

**v1.0.0**

* Initial release
2 changes: 1 addition & 1 deletion LICENSE.txt
@@ -1,4 +1,4 @@
Copyright (c) 2018 Joe Todd
Copyright (c) 2019 Joe Todd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
12 changes: 8 additions & 4 deletions README.rst
Expand Up @@ -27,7 +27,12 @@ Dependencies

apt-get install libsoundio-dev

Ubuntu distributions link to an older version of libsoundio,
* Windows

- Download binaries from `libsound.io <http://libsound.io>`_
- Copy the contents of the download into a folder at ``C:\\ProgramData\libsoundio``

Some Ubuntu distributions link to an older version of libsoundio,
so to use the latest version you will need to install from `source <http://libsound.io/#releases>`_.


Expand All @@ -53,9 +58,8 @@ Some of the examples require `pysoundfile <https://pysoundfile.readthedocs.io/en

pip install pysoundfile

* macOS ::

brew install libsndfile
On Windows and OS X, this will also install the library libsndfile. On Linux you will need
to install the library as well.

* Ubuntu / Debian ::

Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Expand Up @@ -8,7 +8,6 @@

.. include:: ./constants.rst


API Reference
-------------

Expand All @@ -19,6 +18,7 @@ API Reference

.. only:: html

.. include:: ../CHANGELOG.rst

Index
=====
Expand Down
2 changes: 1 addition & 1 deletion examples/record.py
Expand Up @@ -52,7 +52,7 @@ def callback(self, data, length):
)
parser.add_argument('outfile', help='WAV output file name')
parser.add_argument('--backend', type=int, help='Backend to use (optional)')
parser.add_argument('--blocksize', type=int, help='Block size (optional)')
parser.add_argument('--blocksize', type=int, default=4096, help='Block size (optional)')
parser.add_argument('--rate', type=int, default=44100, help='Sample rate (optional)')
parser.add_argument('--channels', type=int, default=2, help='Mono or stereo (optional)')
parser.add_argument('--device', type=int, help='Input device id (optional)')
Expand Down
2 changes: 1 addition & 1 deletion examples/sine.py
Expand Up @@ -58,7 +58,7 @@ def callback(self, data, length):
)
parser.add_argument('--freq', default=442.0, help='Note frequency (optional)')
parser.add_argument('--backend', type=int, help='Backend to use (optional)')
parser.add_argument('--blocksize', type=int, help='Block size (optional)')
parser.add_argument('--blocksize', type=int, default=4096, help='Block size (optional)')
parser.add_argument('--rate', type=int, default=44100, help='Sample rate (optional)')
parser.add_argument('--device', type=int, help='Output device id (optional)')
args = parser.parse_args()
Expand Down
4 changes: 2 additions & 2 deletions pysoundio/__init__.py
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018 Joe Todd
# Copyright (c) 2019 Joe Todd
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand All @@ -21,7 +21,7 @@

import sys

__version__ = '1.0.0'
__version__ = '1.1.0'


try:
Expand Down
36 changes: 32 additions & 4 deletions pysoundio/_soundiox.c
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Joe Todd
* Copyright (c) 2019 Joe Todd
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
Expand Down Expand Up @@ -278,6 +278,11 @@ static PyMethodDef soundio_methods[] = {
pysoundio__outstream_get_latency, METH_VARARGS,
"get next output frame length in seconds"
},
{
"outstream_set_volume",
pysoundio__outstream_set_volume, METH_VARARGS,
"set output stream volume"
},
{
"input_ring_buffer_create",
pysoundio__input_ring_buffer_create, METH_VARARGS,
Expand Down Expand Up @@ -489,9 +494,15 @@ pysoundio__version_string(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, ""))
return NULL;

// Older Ubuntu versions don't include this
const char *version = "libsoundio";
return Py_BuildValue("s", version);
if (sizeof(struct SoundIoOutStream) < 200) { // < v2.0.0
const char *version = "-.-.-";
return Py_BuildValue("s", version);
} else {
char version[6];
sprintf(version, "%d.%d.%d", soundio_version_major(),
soundio_version_minor(), soundio_version_patch());
return Py_BuildValue("s", version);
}
}

static PyObject *
Expand Down Expand Up @@ -1242,6 +1253,23 @@ pysoundio__outstream_get_latency(PyObject *self, PyObject *args)
return Py_BuildValue("i", seconds);
}

static PyObject *
pysoundio__outstream_set_volume(PyObject *self, PyObject *args)
{
double volume;
int new_volume;

if (!PyArg_ParseTuple(args, "d", &volume))
return NULL;

if (sizeof(struct SoundIoOutStream) < 200) { // < v2.0.0
new_volume = -1;
} else {
new_volume = soundio_outstream_set_volume(rc.output_stream, volume);
}

return Py_BuildValue("i", new_volume);
}

/*************************************************************
* Ring Buffer API
Expand Down
2 changes: 2 additions & 0 deletions pysoundio/_soundiox.h
Expand Up @@ -142,6 +142,8 @@ static PyObject *
pysoundio__outstream_clear_buffer(PyObject *self, PyObject *args);
static PyObject *
pysoundio__outstream_get_latency(PyObject *self, PyObject *args);
static PyObject *
pysoundio__outstream_set_volume(PyObject *self, PyObject *args);

/**
* Ring Buffer API
Expand Down
69 changes: 47 additions & 22 deletions pysoundio/pysoundio.py
Expand Up @@ -96,6 +96,11 @@ def __init__(self, backend=None):
soundio.connect_backend(backend)
else:
soundio.connect()

if self.version < '2.0.0':
if ('volume', _ctypes.c_float) in SoundIoOutStream._fields_:
SoundIoOutStream._fields_.remove(('volume', _ctypes.c_float))

self.flush()

def close(self):
Expand All @@ -105,33 +110,40 @@ def close(self):
"""
if self.input['stream']:
soundio.instream_destroy()
self.input['stream'] = None
del self.input['stream']
if self.output['stream']:
soundio.outstream_destroy()
self.output['stream'] = None
del self.output['stream']
if self.input['buffer']:
soundio.ring_buffer_destroy(self.input['buffer'])
self.input['buffer'] = None
del self.input['buffer']
if self.output['buffer']:
soundio.ring_buffer_destroy(self.output['buffer'])
self.output['buffer'] = None
del self.output['buffer']
if self.input['device']:
soundio.device_unref(self.input['device'])
self.input['device'] = None
del self.input['device']
if self.output['device']:
soundio.device_unref(self.output['device'])
self.output['device'] = None
del self.output['device']
if self._soundio:
soundio.disconnect()
soundio.destroy()
self._soundio = None
del self._soundio

def flush(self):
"""
Atomically update information for all connected devices.
"""
soundio.flush()

@property
def version(self):
"""
Returns the current version of libsoundio
"""
return soundio.version_string()

@property
def backend_count(self):
"""
Expand Down Expand Up @@ -419,50 +431,50 @@ def _get_default_layout(self, channels):
"""
return soundio.channel_layout_get_default(channels)

def get_bytes_per_frame(self, device, channels):
def get_bytes_per_frame(self, format, channels):
"""
Get the number of bytes per frame
Parameters
----------
device: (PySoundIoDevice) device
format: (SoundIoFormat) format
channels: (int) number of channels
Returns
-------
(int) number of bytes per frame
"""
return soundio.get_bytes_per_frame(device, channels)
return soundio.get_bytes_per_frame(format, channels)

def get_bytes_per_sample(self, device):
def get_bytes_per_sample(self, format):
"""
Get the number of bytes per sample
Parameters
----------
device: (PySoundIoDevice) device
format: (SoundIoFormat) format
Returns
-------
(int) number of bytes per sample
"""
return soundio.get_bytes_per_sample(device)
return soundio.get_bytes_per_sample(format)

def get_bytes_per_second(self, device, channels, sample_rate):
def get_bytes_per_second(self, format, channels, sample_rate):
"""
Get the number of bytes per second
Parameters
----------
device: (PySoundIoDevice) device
format: (SoundIoFormat) format
channels (int) number of channels
sample_rate (int) sample rate
Returns
-------
(int) number of bytes per second
"""
return soundio.get_bytes_per_second(device, channels, sample_rate)
return soundio.get_bytes_per_second(format, channels, sample_rate)

def _create_input_ring_buffer(self, capacity):
"""
Expand Down Expand Up @@ -530,7 +542,7 @@ def get_input_latency(self, out_latency):
Parameters
----------
out_latency: (int) output latency in seconds
out_latency: (float) output latency in seconds
"""
return soundio.instream_get_latency(out_latency)

Expand Down Expand Up @@ -625,9 +637,9 @@ def overflow_callback():
self._create_input_stream()
self._open_input_stream()
pystream = _ctypes.cast(self.input['stream'], _ctypes.POINTER(SoundIoInStream))
self.input['bytes_per_frame'] = pystream.contents.bytes_per_frame
self.input['bytes_per_frame'] = self.get_bytes_per_frame(self.input['format'], channels)
capacity = (DEFAULT_RING_BUFFER_DURATION *
pystream.contents.sample_rate * pystream.contents.bytes_per_frame)
pystream.contents.sample_rate * self.input['bytes_per_frame'])
self._create_input_ring_buffer(capacity)
self._start_input_stream()
self.flush()
Expand Down Expand Up @@ -705,10 +717,23 @@ def get_output_latency(self, out_latency):
Parameters
----------
out_latency: (int) output latency in seconds
out_latency: (float) output latency in seconds
"""
return soundio.outstream_get_latency(out_latency)

def set_output_volume(self, volume):
"""
Set the output stream volume.
Parameters
----------
volume: (float) output volume from 0 - 1.0
"""
if self.version >= '2.0.0':
return soundio.outstream_set_volume(volume)
else:
raise NotImplementedError('Not implemented in < 2.0.0')

def start_output_stream(self, device_id=None,
sample_rate=None, dtype=None,
block_size=None, channels=None,
Expand Down Expand Up @@ -789,9 +814,9 @@ def underflow_callback():
self._create_output_stream()
self._open_output_stream()
pystream = _ctypes.cast(self.output['stream'], _ctypes.POINTER(SoundIoOutStream))
self.output['bytes_per_frame'] = pystream.contents.bytes_per_frame
self.output['bytes_per_frame'] = self.get_bytes_per_frame(self.output['format'], channels)
capacity = (DEFAULT_RING_BUFFER_DURATION *
pystream.contents.sample_rate * pystream.contents.bytes_per_frame)
pystream.contents.sample_rate * self.output['bytes_per_frame'])
self._create_output_ring_buffer(capacity)
self._clear_output_buffer()
self._start_output_stream()
Expand Down
1 change: 1 addition & 0 deletions pysoundio/structures.py
Expand Up @@ -143,6 +143,7 @@ class SoundIoOutStream(_ctypes.Structure):
('sample_rate', _ctypes.c_int),
('layout', SoundIoChannelLayout),
('software_latency', _ctypes.c_double),
('volume', _ctypes.c_float),
('userdata', _ctypes.c_void_p),
('write_callback', SoundIoWriteCallback),
('underflow_callback', SoundIoUnderflowCallback),
Expand Down

0 comments on commit 9702ff1

Please sign in to comment.