diff pytouhou/ui/music.py @ 421:b1248bab2d0f

Add back music and SFX playback using SDL_mixer instead of pyglet, and add FLAC and Vorbis support.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 16 Jul 2013 21:07:15 +0200
parents d8aab27a2ab2
children
line wrap: on
line diff
--- a/pytouhou/ui/music.py
+++ b/pytouhou/ui/music.py
@@ -14,79 +14,13 @@
 
 
 from os.path import join
-
-from pyglet.media import AudioData, AudioFormat, StaticSource, Player
-from pyglet.media.riff import WaveSource
-
-
+from glob import glob
+from pytouhou.lib import sdl
 from pytouhou.utils.helpers import get_logger
 
 logger = get_logger(__name__)
 
 
-class InfiniteWaveSource(WaveSource):
-    def __init__(self, filename, start, end, file=None):
-        WaveSource.__init__(self, filename, file)
-
-        self._start = self.audio_format.bytes_per_sample * start
-        self._end = self.audio_format.bytes_per_sample * end
-
-        if self._end > self._max_offset:
-            raise Exception('Music ends after the end of the file.')
-
-        self._duration = None
-
-
-    def _get_audio_data(self, bytes):
-        bytes -= bytes % self.audio_format.bytes_per_sample
-
-        data = b''
-        length = bytes
-        while True:
-            size = min(length, self._end - self._offset)
-            data += self._file.read(size)
-            if size == length:
-                break
-
-            self._offset = self._start
-            self._file.seek(self._offset + self._start_offset)
-            length -= size
-
-        self._offset += length
-
-        timestamp = float(self._offset) / self.audio_format.bytes_per_second
-        duration = float(bytes) / self.audio_format.bytes_per_second
-
-        return AudioData(data, bytes, timestamp, duration)
-
-
-    def seek(self, timestamp):
-        raise NotImplementedError('irrelevant')
-
-
-class ZwavSource(InfiniteWaveSource):
-    def __init__(self, filename, format, file=None):
-        if file is None:
-            file = open(filename, 'rb')
-
-        self._file = file
-
-        magic = self._file.read(4)
-        assert b'ZWAV' == magic
-
-        self.audio_format = AudioFormat(
-            channels=format.wChannels,
-            sample_size=format.wBitsPerSample,
-            sample_rate=format.dwSamplesPerSec)
-
-        self._start_offset = 0
-        self._offset = format.intro
-
-        self._file.seek(self._offset)
-        self._start = format.intro + format.start
-        self._end = format.intro + format.duration
-
-
 class MusicPlayer(object):
     def __init__(self, resource_loader, bgms):
         self.bgms = []
@@ -99,69 +33,63 @@ class MusicPlayer(object):
                 track = resource_loader.get_track(posname)
             except KeyError:
                 self.bgms.append(None)
-                logger.warn('Music description not found: %s', posname)
+                logger.warn(u'Music description “%s” not found.', posname)
                 continue
-            wavname = join(resource_loader.game_dir, bgm[1].replace('.mid', '.wav'))
-            try:
-                source = InfiniteWaveSource(wavname, track.start, track.end)
-            except IOError:
-                source = None
-            self.bgms.append(source)
-
-        self.player = Player()
-
-
-    def pause(self):
-        self.player.pause()
-
+            globname = join(resource_loader.game_dir, bgm[1]).replace('.mid', '.*')
+            filenames = glob(globname)
+            for filename in reversed(filenames):
+                try:
+                    source = sdl.load_music(filename)
+                except sdl.SDLError as error:
+                    logger.debug(u'Music file “%s” unreadable: %s', filename, error)
+                    continue
+                else:
+                    source.set_loop_points(track.start / 44100., track.end / 44100.) #TODO: retrieve the sample rate from the actual track.
+                    self.bgms.append(source)
+                    logger.debug(u'Music file “%s” opened.', filename)
+                    break
+            else:
+                self.bgms.append(None)
+                logger.warn(u'No working music file for “%s”, disabling bgm.', globname)
 
     def play(self, index):
         bgm = self.bgms[index]
-        if self.player.playing:
-            self.player.next()
         if bgm:
-            self.player.queue(bgm)
-        self.player.play()
+            bgm.play(-1)
 
 
 class SFXPlayer(object):
     def __init__(self, loader, volume=.42):
         self.loader = loader
-        self.players = {}
+        self.channels = {}
         self.sounds = {}
         self.volume = volume
-
+        self.next_channel = 0
 
-    def get_player(self, name):
-        if name not in self.players:
-            self.players[name] = Player()
-            self.players[name].volume = self.volume
-        return self.players[name]
-
+    def get_channel(self, name):
+        if name not in self.channels:
+            self.channels[name] = self.next_channel
+            self.next_channel += 1
+        return self.channels[name]
 
     def get_sound(self, name):
         if name not in self.sounds:
             wave_file = self.loader.get_file(name)
-            self.sounds[name] = StaticSource(WaveSource(name, wave_file))
+            self.sounds[name] = sdl.load_chunk(wave_file)
+            self.sounds[name].volume = self.volume
         return self.sounds[name]
 
-
     def play(self, name, volume=None):
         sound = self.get_sound(name)
-        player = self.get_player(name)
+        channel = self.get_channel(name)
         if volume:
-            player.volume = volume
-        if player.playing:
-            player.next()
-        if sound:
-            player.queue(sound)
-        player.play()
+            sdl.mix_volume(channel, volume)
+        sound.play(channel, 0)
 
 
 class NullPlayer(object):
     def __init__(self, loader=None, bgms=None):
         pass
 
-
-    def play(self, name):
+    def play(self, name, volume=None):
         pass