Пример #1
0
 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
Пример #2
0
 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
Пример #3
0
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
Пример #4
0
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.")