Browse Source

Add MusicPlayer.py

This new MusicPlayer.py replaces the old music_player.py. It is imported into UPBGE as a component, and replaces two sensors, one controller and an actuator. Controls should be as expected, but are welcome to change (especially for keyboard input)
Farmerjoe12 3 years ago
parent
commit
14869f9e21
1 changed files with 161 additions and 0 deletions
  1. 161
    0
      MusicPlayer.py

+ 161
- 0
MusicPlayer.py View File

@@ -0,0 +1,161 @@
1
+import bge
2
+import os
3
+import aud
4
+import random
5
+import glob
6
+from DList import DoubleList
7
+from collections import OrderedDict
8
+from tinytag import TinyTag
9
+
10
+""" This is the Music Player as a component """
11
+class MusicPlayer(bge.types.KX_PythonComponent):
12
+
13
+    args = OrderedDict([])    
14
+
15
+    def start(self, args):
16
+        # dictionary
17
+        self.dictionary = bge.logic.globalDict
18
+        
19
+        # get mp3 files from the disk and create a list
20
+        self.directory = bge.logic.expandPath('//Music')
21
+        file_name = self.directory + '\\*.mp3'
22
+        file_list =  glob.glob(file_name)
23
+        
24
+        # use the mp3 list to make a playlist of nodes
25
+        self.playlist = DoubleList()
26
+        for name in file_list:
27
+            self.playlist.append(name)
28
+        
29
+        # previously played list of nodes
30
+        self.alreadyPlayed = DoubleList()
31
+        
32
+        # get a random song from the playlist, 
33
+        # remove it from the playlist
34
+        # add it to the alreadyPlayed list
35
+        # NOTICE: currentNode is a reference to a NODE in a list, if you want to play the song inside the node, use .data
36
+        self.currentNode = self.playlist.get(random.randint(0, self.playlist.getLength()))
37
+        self.nowPlaying = self.currentNode.getData()
38
+        self.playlist.remove(self.currentNode)
39
+        self.alreadyPlayed.append(self.nowPlaying)
40
+        print("Now Playing: " + self.nowPlaying)
41
+        self.setTag()
42
+        self.isPlaying = False
43
+
44
+        # create audio devices
45
+        self.device = aud.device()
46
+        self.factory = aud.Factory(self.nowPlaying)
47
+        self.handle = None        
48
+    
49
+    """ Update is called once every frame, and this is where
50
+        any input handling should go
51
+        
52
+        Controller Buttons: 
53
+        Y-Button - Play/Pause
54
+        LB       - Previous Track
55
+        RB       - Next Track
56
+        
57
+        TODO: Keyboard Buttons if these aren't alright
58
+        P        - Play/Pause
59
+        Pad Plus - Next Track
60
+        Pad Minus- Prev Track
61
+    """
62
+    def update(self):
63
+        keyboard = bge.logic.keyboard.events
64
+        up_dict = bge.logic.globalDict
65
+        #print(dictionary)
66
+        pKey = keyboard[bge.events.PKEY]
67
+        pPlus = keyboard[bge.events.PADPLUSKEY]
68
+        pMinus = keyboard[bge.events.PADMINUS]
69
+        lb = up_dict['lBump']
70
+        last_lb = up_dict['last_lBump']
71
+        rb = up_dict['rBump']
72
+        last_rb = up_dict['last_rBump']
73
+        y = up_dict['yBut']
74
+        last_y = up_dict['last_yBut']
75
+        JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
76
+        
77
+        # Music controls only during pause/replay
78
+        if up_dict['npause'] == True or up_dict['playback'] == True:
79
+            #stop/play
80
+            if (y == False and last_y == True) or pKey == JUST_ACTIVATED:
81
+                if self.isPlaying:
82
+                    self.stopMusic()
83
+                else:
84
+                    self.playMusic()
85
+            # Prev/Next
86
+            if self.isPlaying and self.handle.status:
87
+                if pMinus == JUST_ACTIVATED or (lb == False and last_lb == True):
88
+                    self.prevSong()
89
+                
90
+                if pPlus == JUST_ACTIVATED or (rb == False and last_rb == True):
91
+                    self.nextSong()
92
+        # if song ends, play next song
93
+        if self.isPlaying and not self.handle.status:
94
+            self.nextSong()
95
+
96
+    """ get info about song using TinyTag, then print to console """
97
+    def setTag(self):                
98
+        self.currTrackPath = os.path.join(self.directory, self.nowPlaying)
99
+        tag = TinyTag.get(self.currTrackPath)
100
+        self.currArtist = tag.artist
101
+        self.currTrackTitle = tag.title
102
+        self.dictionary['mu_artist'] = self.currArtist
103
+        self.dictionary['mu_title'] = self.currTrackTitle
104
+                
105
+        print('Artist: %s' % self.currArtist, 
106
+                ' Track: %s' % self.currTrackTitle)
107
+
108
+    def playMusic(self):
109
+        print('Play Music')
110
+        self.setTag()
111
+        self.handle = self.device.play(self.factory)
112
+        self.isPlaying = True
113
+        
114
+    def stopMusic(self):
115
+        print('Stop Music')
116
+        self.handle.stop()
117
+        self.isPlaying = False
118
+        
119
+    def nextSong(self):
120
+        print('Next Song')
121
+        # stop the current song
122
+        self.handle.stop()
123
+        
124
+        # get a song from the playlist
125
+        self.currentNode = self.playlist.get(random.randint(0, self.playlist.getLength()))
126
+        self.nowPlaying = self.currentNode.getData()
127
+        self.playlist.remove(self.currentNode)
128
+                
129
+        # add the song to the already played list
130
+        self.alreadyPlayed.append(self.nowPlaying)  
131
+        
132
+        # start the song
133
+        self.factory = aud.Factory(self.nowPlaying)
134
+        self.handle = self.device.play(self.factory)
135
+        self.setTag()
136
+        
137
+        # If playlist is empty, re-fill it
138
+        if self.playlist.getLength() == 0:
139
+            file_name = self.directory + '\\*.mp3'
140
+            file_list =  glob.glob(file_name)
141
+            for name in file_list:
142
+                self.playlist.append(name)
143
+        
144
+    """ Note on first call of this method, the current node will be equal to the tail of the already played list, 
145
+        however, it will be a node from a different list. We need to set current node equal to the tail node
146
+        of the already played list so that we can iterate through that list, instead of the other list """
147
+    def prevSong(self):
148
+        print('Prev Song')
149
+        # stop the current song
150
+        self.handle.stop()        
151
+        
152
+        if self.currentNode.getData() == self.alreadyPlayed.getTail().getData():
153
+            self.currentNode = self.alreadyPlayed.getTail()
154
+            
155
+        self.currentNode = self.currentNode.getPrev()
156
+        self.nowPlaying = self.currentNode.getData()
157
+        
158
+        # start the song
159
+        self.factory = aud.Factory(self.nowPlaying)
160
+        self.handle = self.device.play(self.factory)
161
+        self.setTag()

Loading…
Cancel
Save