Play several bars (a list of Bar objects) at the same time. A list of channels should also be provided. The tempo can be changed by providing one or more of the NoteContainers with a bpm argument.
(self, bars, channels, bpm=120)
| 234 | return {"bpm": bpm} |
| 235 | |
| 236 | def play_Bars(self, bars, channels, bpm=120): |
| 237 | """Play several bars (a list of Bar objects) at the same time. |
| 238 | |
| 239 | A list of channels should also be provided. The tempo can be changed |
| 240 | by providing one or more of the NoteContainers with a bpm argument. |
| 241 | """ |
| 242 | self.notify_listeners( |
| 243 | self.MSG_PLAY_BARS, {"bars": bars, "channels": channels, "bpm": bpm} |
| 244 | ) |
| 245 | qn_length = 60.0 / bpm # length of a quarter note |
| 246 | tick = 0.0 # place in beat from 0.0 to bar.length |
| 247 | cur = [0] * len(bars) # keeps the index of the NoteContainer under |
| 248 | # investigation in each of the bars |
| 249 | playing = [] # The NoteContainers being played. |
| 250 | |
| 251 | while tick < bars[0].length: |
| 252 | # Prepare a and play a list of NoteContainers that are ready for it. |
| 253 | # The list `playing_new` holds both the duration and the |
| 254 | # NoteContainer. |
| 255 | playing_new = [] |
| 256 | for (n, x) in enumerate(cur): |
| 257 | (start_tick, note_length, nc) = bars[n][x] |
| 258 | if start_tick <= tick: |
| 259 | self.play_NoteContainer(nc, channels[n]) |
| 260 | playing_new.append([note_length, n]) |
| 261 | playing.append([note_length, nc, channels[n], n]) |
| 262 | |
| 263 | # Change the length of a quarter note if the NoteContainer |
| 264 | # has a bpm attribute |
| 265 | if hasattr(nc, "bpm"): |
| 266 | bpm = nc.bpm |
| 267 | qn_length = 60.0 / bpm |
| 268 | |
| 269 | # Sort the list and sleep for the shortest duration |
| 270 | if len(playing_new) != 0: |
| 271 | playing_new.sort() |
| 272 | shortest = playing_new[-1][0] |
| 273 | ms = qn_length * (4.0 / shortest) |
| 274 | self.sleep(ms) |
| 275 | self.notify_listeners(self.MSG_SLEEP, {"s": ms}) |
| 276 | else: |
| 277 | # If somehow, playing_new doesn't contain any notes (something |
| 278 | # that shouldn't happen when the bar was filled properly), we |
| 279 | # make sure that at least the notes that are still playing get |
| 280 | # handled correctly. |
| 281 | if len(playing) != 0: |
| 282 | playing.sort() |
| 283 | shortest = playing[-1][0] |
| 284 | ms = qn_length * (4.0 / shortest) |
| 285 | self.sleep(ms) |
| 286 | self.notify_listeners(self.MSG_SLEEP, {"s": ms}) |
| 287 | else: |
| 288 | # warning: this could lead to some strange behaviour. OTOH. |
| 289 | # Leaving gaps is not the way Bar works. should we do an |
| 290 | # integrity check on bars first? |
| 291 | return {} |
| 292 | |
| 293 | # Add shortest interval to tick |