def init(self, frequency=22050, size=-16, channels=2, buffer=4096): """ Mixer initialization. Argument sampled frequency, bit size, channels, and buffer. Currently implements PCM 16-bit audio. Plays WAV, AIFF, and AU sampled audio. To specify the BigEndian format of AIFF and AU, use -16L for size. The mixing is done by Mixer.class, compiled with 'javac Mixer.java'. When a JAR is created, include with 'jar uvf Pyj2d_App.jar pyj2d/Mixer.class'. """ if not self._initialized: encoding = {True:AudioFormat.Encoding.PCM_SIGNED, False:AudioFormat.Encoding.PCM_UNSIGNED}[size<0] channels = {True:1, False:2}[channels<=1] framesize = int((abs(size)/8) * channels) isBigEndian = isinstance(size,long) self._audio_format = AudioFormat(encoding, int(frequency), int(abs(size)), channels, framesize, int(frequency), isBigEndian) self._bufferSize = buffer try: self._mixer = AudioMixer(self._audio_format, self._bufferSize) except TypeError: self._mixer = None return None if not self._mixer.isInitialized(): return None self._bufferSize = self._mixer.getBufferSize() self._byteArray = jarray.zeros(self._bufferSize, 'b') self._initialized = True self._thread = Thread(self) self._thread.start() return None
def init(self, frequency=22050, size=-16, channels=2, buffer=4096): """ Mixer initialization. Argument sampled frequency, bit size, channels, and buffer. Currently implements PCM 16-bit audio. Plays WAV, AIFF, and AU sampled audio. To specify BigEndian format of AIFF and AU, use size of float type. The mixing is done by Mixer.class, compiled with 'javac Mixer.java'. For JAR creation include with 'jar uvf App.jar pyj2d/Mixer.class'. """ if not self._initialized: encoding = {True: AudioFormat.Encoding.PCM_SIGNED, False: AudioFormat.Encoding.PCM_UNSIGNED}[size<0] channels = {True:1, False:2}[channels<=1] framesize = int((abs(size)/8) * channels) isBigEndian = isinstance(size, float) self._audio_format = AudioFormat(encoding, int(frequency), int(abs(size)), channels, framesize, int(frequency), isBigEndian) self._bufferSize = buffer try: self._mixer = AudioMixer(self._audio_format, self._bufferSize) except TypeError: self._mixer = None return None if not self._mixer.isInitialized(): return None self._byteRate = ( self._audio_format.getSampleRate() * self._audio_format.getChannels() * (self._audio_format.getSampleSizeInBits()/8) ) self._bufferSize = self._mixer.getBufferSize() self._byteArray = jarray.zeros(self._bufferSize, 'b') for id in range(self._channel_max): self._get_channel(id) self.music = Music() self._initialized = True self._thread = Thread(self) self._thread.start() return None
class Mixer(Runnable): """ **pyj2d.mixer** * pyj2d.mixer.init * pyj2d.mixer.quit * pyj2d.mixer.get_init * pyj2d.mixer.stop * pyj2d.mixer.pause * pyj2d.mixer.unpause * pyj2d.mixer.set_num_channels * pyj2d.mixer.get_num_channels * pyj2d.mixer.set_reserved * pyj2d.mixer.find_channel * pyj2d.mixer.get_busy * pyj2d.mixer.Sound * pyj2d.mixer.Channel """ def __init__(self): self._mixer = None Sound._mixer = self Channel._mixer = self self.Sound = Sound self.Channel = Channel self._channel_max = 8 self._channels = {} self._sounds = {} self._channel_reserved = [] self._channel_paused = [] self._channel_reserves = [id for id in range(self._channel_max-1,-1,-1)] self._channel_pool = [] self._lines = {} self._line_num = 0 self._thread = None self._initialized = False self._nonimplemented_methods() def init(self, frequency=22050, size=-16, channels=2, buffer=4096): """ Mixer initialization. Argument sampled frequency, bit size, channels, and buffer. Currently implements PCM 16-bit audio. Plays WAV, AIFF, and AU sampled audio. To specify the BigEndian format of AIFF and AU, use -16L for size. The mixing is done by Mixer.class, compiled with 'javac Mixer.java'. When a JAR is created, include with 'jar uvf Pyj2d_App.jar pyj2d/Mixer.class'. """ if not self._initialized: encoding = {True:AudioFormat.Encoding.PCM_SIGNED, False:AudioFormat.Encoding.PCM_UNSIGNED}[size<0] channels = {True:1, False:2}[channels<=1] framesize = int((abs(size)/8) * channels) isBigEndian = isinstance(size,long) self._audio_format = AudioFormat(encoding, int(frequency), int(abs(size)), channels, framesize, int(frequency), isBigEndian) self._bufferSize = buffer try: self._mixer = AudioMixer(self._audio_format, self._bufferSize) except TypeError: self._mixer = None return None if not self._mixer.isInitialized(): return None self._bufferSize = self._mixer.getBufferSize() self._byteArray = jarray.zeros(self._bufferSize, 'b') self._initialized = True self._thread = Thread(self) self._thread.start() return None def pre_init(self, frequency=22050, size=-16, channels=2, buffer=4096): """ Mixer initialization. """ self.init(frequency, size, channels, buffer) return None def quit(self): """ Stop mixer processing and release resources. """ self._initialized = False def _quit(self): self.stop() try: self._mixer.quit() except AttributeError: pass self._mixer = None def get_init(self): """ Get the audio format initialized. """ if self._initialized: frequency = int(self._audio_format.sampleRate) format = self._audio_format.sampleSizeInBits * {True:1,False:-1}[self._audio_format.bigEndian] channels = self._audio_format.channels return (frequency, format, channels) else: return None def stop(self): """ Stop mixer channels. """ for id in self._channel_pool: self._channels[id].stop() return None def pause(self): """ Pause mixer channels. """ for id in self._channel_pool: try: if self._channels[id]._active: self._channel_paused.append(id) self._channels[id].pause() except AttributeError: continue return None def unpause(self): """ Unpause mixer channels. """ for id in self._channel_paused: self._channels[id].unpause() self.channel_paused = [] return None def set_num_channels(self, count): """ Set maximum mixer channels. Argument channel count. """ if count >= self._channel_max: for id in range(self._channel_max, count): self._channels[id] = None self._channel_max = count elif count >= 0: for id in range(count, self._channel_max): self._channels[id].stop() del self._channels[id] self._channel_max = count return None def get_num_channels(self): """ Get maximum mixer channels. """ return self._channel_max def set_reserved(self, count): """ Reserve channel. Argument reserved channel count. """ if count > self._channel_max: count = self._channel_max reserved_len = len(self._channel_reserved) if reserved_len: if reserved_len >= count: for i in range(reserved_len-count): id = self._channel_reserved.pop() self._channels[id]._reserved = False self._channel_pool.append(id) count = 0 else: count -= len(self._channel_reserved) for id in range(reserved_len, count+reserved_len): try: self._channels[id]._reserved = True except AttributeError: self._channels[id] = Channel(id) try: self._channel_pool.remove(id) except ValueError: pass self._channel_reserved.append(id) return None def find_channel(self, force=False): """ Get an inactive mixer channel. Optional force attribute return longest running channel if all active. """ try: channel = self._channel_reserves.pop() try: return self._channels[channel] except KeyError: channel = Channel(channel) return channel except IndexError: for id in self._channel_pool: if not self._channels[id]._active: return self._channels[id] else: if force: channel = None longest = 0 for id in self._channel_pool: try: duration = self._channels[id]._stream.getMicrosecondPosition() if duration > longest: longest = duration channel = self._channels[id] except AttributeError: channel = self._channels[id] break try: channel.stop() return channel except AttributeError: return None else: return None def get_busy(self): """ Check if mixer channels are actively processing. """ for id in self._channel_pool: try: if self._channels[id]._active: return True except AttributeError: continue return False def run(self): while self._initialized: channel_active = [self._channels[id] for id in self._channel_pool if self._channels[id]._active] if not channel_active: try: self._thread.sleep(1) except InterruptedException: Thread.currentThread().interrupt() self.quit() continue if len(channel_active) > 1: for channel in channel_active: try: data, data_len, lvol, rvol = channel._get() except AttributeError: continue self._mixer.setAudioData(data, data_len, lvol, rvol) data_len = self._mixer.getAudioData(self._byteArray) if data_len > 0: try: self._mixer.write(self._byteArray, 0, data_len) except IllegalArgumentException: nonIntegralByte = data_len % self._audio_format.getFrameSize() if nonIntegralByte: data_len -= nonIntegralByte try: self._mixer.write(self._byteArray, 0, data_len) except (IllegalArgumentException, LineUnavailableException): pass except LineUnavailableException: pass else: try: data, data_len, lvol, rvol = channel_active[0]._get() except AttributeError: data_len = 0 if data_len > 0: if lvol < 1.0 or rvol < 1.0: data = self._mixer.processVolume(data, data_len, lvol, rvol) try: self._mixer.write(data, 0, data_len) except IllegalArgumentException: nonIntegralByte = data_len % self._audio_format.getFrameSize() if nonIntegralByte: data_len -= nonIntegralByte try: self._mixer.write(data, 0, data_len) except (IllegalArgumentException, LineUnavailableException): pass except LineUnavailableException: pass self._quit() def _register_channel(self, channel): id = channel._id if id < self._channel_max: try: if self._channels[id]._sound: channel._sound = self._channels[id]._sound channel._stream = self._channels[id]._stream self._channels[id] = channel except KeyError: self._channels[id] = channel self._channel_pool.append(id) else: raise AttributeError("Channel not available.") def _register_sound(self, sound): self._sounds[sound._id] = sound def _nonimplemented_methods(self): """ Non-implemented methods. """ self.fadeout = lambda *arg: None
class Mixer(Runnable): """ **pyj2d.mixer** * pyj2d.mixer.init * pyj2d.mixer.quit * pyj2d.mixer.get_init * pyj2d.mixer.stop * pyj2d.mixer.pause * pyj2d.mixer.unpause * pyj2d.mixer.fadeout * pyj2d.mixer.set_num_channels * pyj2d.mixer.get_num_channels * pyj2d.mixer.set_reserved * pyj2d.mixer.find_channel * pyj2d.mixer.get_busy * pyj2d.mixer.Sound * pyj2d.mixer.Channel * pyj2d.mixer.music """ def __init__(self): self._mixer = None Sound._mixer = self Channel._mixer = self self.Sound = Sound self.Channel = self._get_channel self.music = None self._channel_max = 8 self._channels = {} self._channel_available = ConcurrentLinkedDeque() self._channel_available.addAll(list(range(self._channel_max))) self._channel_active = ConcurrentLinkedDeque() self._channel_reserved = ConcurrentLinkedDeque() self._channel_reserved_num = 0 self._thread = None self.run = self._process self._active = AtomicBoolean(False) self._initialized = False def init(self, frequency=22050, size=-16, channels=2, buffer=4096): """ Mixer initialization. Argument sampled frequency, bit size, channels, and buffer. Currently implements PCM 16-bit audio. Plays WAV, AIFF, and AU sampled audio. To specify BigEndian format of AIFF and AU, use size of float type. The mixing is done by Mixer.class, compiled with 'javac Mixer.java'. For JAR creation include with 'jar uvf App.jar pyj2d/Mixer.class'. """ if not self._initialized: encoding = {True: AudioFormat.Encoding.PCM_SIGNED, False: AudioFormat.Encoding.PCM_UNSIGNED}[size<0] channels = {True:1, False:2}[channels<=1] framesize = int((abs(size)/8) * channels) isBigEndian = isinstance(size, float) self._audio_format = AudioFormat(encoding, int(frequency), int(abs(size)), channels, framesize, int(frequency), isBigEndian) self._bufferSize = buffer try: self._mixer = AudioMixer(self._audio_format, self._bufferSize) except TypeError: self._mixer = None return None if not self._mixer.isInitialized(): return None self._byteRate = ( self._audio_format.getSampleRate() * self._audio_format.getChannels() * (self._audio_format.getSampleSizeInBits()/8) ) self._bufferSize = self._mixer.getBufferSize() self._byteArray = jarray.zeros(self._bufferSize, 'b') for id in range(self._channel_max): self._get_channel(id) self.music = Music() self._initialized = True self._thread = Thread(self) self._thread.start() return None def pre_init(self, frequency=22050, size=-16, channels=2, buffer=4096): """ Mixer initialization. """ self.init(frequency, size, channels, buffer) return None def quit(self): """ Stop mixer processing and release resources. """ self._initialized = False return None def _quit(self): self.stop() self.music._channel.stop() try: self._mixer.quit() except AttributeError: pass self._mixer = None def get_init(self): """ Get the audio format initialized. """ if self._initialized: frequency = int(self._audio_format.sampleRate) format = ( self._audio_format.sampleSizeInBits * {True:1,False:-1}[self._audio_format.bigEndian] ) channels = self._audio_format.channels return (frequency, format, channels) else: return None def stop(self): """ Stop mixer channels. """ for id in self._channel_active.iterator(): if id > -1: self._channels[id].stop() return None def fadeout(self, time): """ Fadeout mixer channels in given time. """ for id in self._channel_active.iterator(): if id > -1: self._channels[id].fadeout(time) return None def pause(self): """ Pause mixer channels. """ for id in self._channel_active.iterator(): if id > -1: self._channels[id].pause() return None def unpause(self): """ Unpause mixer channels. """ for id in self._channel_active.iterator(): if id > -1: self._channels[id].unpause() return None def set_num_channels(self, count): """ Set maximum mixer channels. Argument channel count. """ if count >= self._channel_max: for id in range(self._channel_max, count): self._get_channel(id) self._channel_available.add(id) self._channel_max = count elif count >= 0: for id in range(count, self._channel_max): if id in self._channels: if self._channels[id] is not None: self._channels[id].stop() del self._channels[id] self._channel_available.remove(id) self._channel_max = count return None def get_num_channels(self): """ Get maximum mixer channels. """ return self._channel_max def set_reserved(self, count): """ Reserve channel. Argument reserved channel count. """ if count > self._channel_max: count = self._channel_max elif count < 0: count = 0 self._channel_reserved_num = count self._channel_reserved.clear() for id in range(self._channel_reserved_num): self._channel_reserved.add(id) self._channel_available.remove(id) return None def find_channel(self, force=False): """ Get an inactive mixer channel. Optional force attribute return longest running channel if all active. """ try: id = self._channel_available.pop() self._channel_available.add(id) return self._channels[id] except NoSuchElementException: pass try: if self._channel_reserved_num: id = self._channel_reserved.pop() self._channel_reserved.add(id) return self._channels[id] except NoSuchElementException: pass if not force: return None longest = None longest_reserved = None for id in self._channel_active.iterator(): if id > self._channel_reserved_num-1: longest = id break elif id > -1: if longest_reserved is None: longest_reserved = id if longest is not None: channel = longest else: if longest_reserved is not None: channel = longest_reserved else: channel = 0 return self._channels[channel] def get_busy(self): """ Check if mixer channels are actively processing. """ for id in self._channel_active.iterator(): if id > -1: if self._channels[id]._active: return True return False def _process(self): while self._initialized: if not self._active.get(): self._idle() continue if self._channel_active.size() > 1: data, data_len = self._mix(self._channel_active) if data_len > 0: self._write(data, data_len) else: try: channel = self._channel_active.getFirst() data, data_len = self._read(channel) except NoSuchElementException: data_len = 0 if data_len > 0: self._write(data, data_len) self._quit() def _idle(self): try: self._thread.sleep(10) except InterruptedException: Thread.currentThread().interrupt() self.quit() def _mix(self, channels): for id in channels.iterator(): channel = self._channels[id] if not channel._active.get(): continue try: data, data_len, lvol, rvol = channel._get() except AttributeError: continue self._mixer.setAudioData(data, data_len, lvol, rvol) data_len = self._mixer.getAudioData(self._byteArray) return self._byteArray, data_len def _read(self, channel): channel = self._channels[channel] if not channel._active.get(): data, data_len = None, 0 else: try: data, data_len, lvol, rvol = channel._get() except AttributeError: data, data_len = None, 0 if data_len: if lvol < 1.0 or rvol < 1.0: data = self._mixer.processVolume(data, data_len, lvol, rvol) return data, data_len def _write(self, data, data_len): try: self._mixer.write(data, 0, data_len) except IllegalArgumentException: nonIntegralByte = data_len % self._audio_format.getFrameSize() if nonIntegralByte: data_len -= nonIntegralByte try: self._mixer.write(data, 0, data_len) except (IllegalArgumentException, LineUnavailableException): pass except LineUnavailableException: pass def _activate_channel(self, id): if id > self._channel_reserved_num-1: self._channel_available.remove(id) else: self._channel_reserved.remove(id) self._channel_active.add(id) self._active.set(True) def _deactivate_channel(self, id): self._channel_active.remove(id) if self._channel_active.isEmpty(): self._active.set(False) def _restore_channel(self, id): if id > self._channel_reserved_num-1: self._channel_available.add(id) elif id > -1: self._channel_reserved.add(id) def _retrieve_channel(self): try: id = self._channel_available.pop() self._channel_active.add(id) self._active.set(True) return self._channels[id] except NoSuchElementException: return None def _get_channel(self, id): if id in self._channels: return self._channels[id] else: return Channel(id) def _register_channel(self, channel): id = channel._id if id < self._channel_max: self._channels[id] = channel else: raise AttributeError("Channel not available.")