diff --git a/CHANGES b/CHANGES index c6be2b40d..6bacf4db9 100644 --- a/CHANGES +++ b/CHANGES @@ -111,6 +111,7 @@ Features: - Qt: State file load/save menu options - Windows installer - Tile viewer now has adjustable width + - Python: Experimental audio API Bugfixes: - PSP2: Fix audio crackling after fast forward - PSP2: Fix audio crackling when buffer is full diff --git a/src/platform/python/_builder.h b/src/platform/python/_builder.h index bc1ee9d40..9a0d2b624 100644 --- a/src/platform/python/_builder.h +++ b/src/platform/python/_builder.h @@ -35,6 +35,7 @@ void free(void*); #include "flags.h" +#include #include #include #include diff --git a/src/platform/python/_builder.py b/src/platform/python/_builder.py index 707703c5b..45518fa4f 100644 --- a/src/platform/python/_builder.py +++ b/src/platform/python/_builder.py @@ -20,6 +20,7 @@ ffi.set_source("mgba._pylib", """ #define inline #include "flags.h" #define OPAQUE_THREADING +#include #include #include #include diff --git a/src/platform/python/mgba/audio.py b/src/platform/python/mgba/audio.py new file mode 100644 index 000000000..a833d0827 --- /dev/null +++ b/src/platform/python/mgba/audio.py @@ -0,0 +1,57 @@ +# Copyright (c) 2013-2018 Jeffrey Pfau +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +from ._pylib import ffi, lib # pylint: disable=no-name-in-module + + +class Buffer(object): + def __init__(self, native, internal_rate): + self._native = native + self._internal_rate = internal_rate + + @property + def available(self): + return lib.blip_samples_avail(self._native) + + def set_rate(self, rate): + lib.blip_set_rates(self._native, self._internal_rate, rate) + + def read(self, samples): + buffer = ffi.new("short[%i]" % samples) + count = self.read_into(buffer, samples, 1, 0) + return buffer[:count] + + def read_into(self, buffer, samples, channels=1, interleave=0): + return lib.blip_read_samples(self._native, ffi.addressof(buffer, interleave), samples, channels == 2) + + def clear(self): + lib.blip_clear(self._native) + + +class StereoBuffer(object): + def __init__(self, left, right): + self._left = left + self._right = right + + @property + def available(self): + return min(self._left.available, self._right.available) + + def set_rate(self, rate): + self._left.set_rate(rate) + self._right.set_rate(rate) + + def read(self, samples): + buffer = ffi.new("short[%i]" % (2 * samples)) + count = self.read_into(buffer, samples) + return buffer[0:2 * count] + + def read_into(self, buffer, samples): + samples = self._left.read_into(buffer, samples, 2, 0) + return self._right.read_into(buffer, samples, 2, 1) + + def clear(self): + self._left.clear() + self._right.clear() diff --git a/src/platform/python/mgba/core.py b/src/platform/python/mgba/core.py index 94b685328..1399b1ad6 100644 --- a/src/platform/python/mgba/core.py +++ b/src/platform/python/mgba/core.py @@ -4,7 +4,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. from ._pylib import ffi, lib # pylint: disable=no-name-in-module -from . import tile +from . import tile, audio from cached_property import cached_property from functools import wraps @@ -225,6 +225,22 @@ class Core(object): def set_video_buffer(self, image): self._core.setVideoBuffer(self._core, image.buffer, image.stride) + @protected + def set_audio_buffer_size(self, size) + self._core.setAudioBufferSize(self._core, size) + + @property + def audio_buffer_size(self): + return self._core.getAudioBufferSize(self._core) + + @protected + def get_audio_channels(self): + return audio.StereoBuffer(self.get_audio_channel(0), self.get_audio_channel(1)); + + @protected + def get_audio_channel(self, channel): + return audio.Buffer(self._core.getAudioChannel(self._core, channel), self.frequency) + @protected def reset(self): self._core.reset(self._core)