@@ -800,9 +800,10 @@ def __init__(self, **keywords):
800
800
Create a new ChannelEvent object.
801
801
802
802
In addition to the keywords inherited from Event, ChannelEvents also
803
- accept the channel keyword .
803
+ accept the channel and program keywords .
804
804
"""
805
805
self .channel = keywords .pop ('channel' , None )
806
+ self .program = keywords .pop ('program' , None )
806
807
super ().__init__ (** keywords )
807
808
808
809
@classmethod
@@ -813,7 +814,7 @@ def _parse(cls, source=None, status=None):
813
814
type = status & 0xf0
814
815
if type not in ChannelEvent ._events :
815
816
raise MIDIError (
816
- 'Encountered an unkown event: {status:X}.' .format (
817
+ 'Encountered an unknown event: {status:X}.' .format (
817
818
status = status ))
818
819
event = ChannelEvent ._events [type ]._parse (source )
819
820
event .channel = channel
@@ -1378,16 +1379,24 @@ def parse(source):
1378
1379
sequence .append (event )
1379
1380
track += 1
1380
1381
1381
- def cumulative (event ):
1382
- return event .time .cumulative
1383
- sequence .sort (key = cumulative )
1384
-
1382
+ sequence .sort (key = sequence ._meta_sort_key )
1383
+ sequence .sort (key = sequence ._cumulative_sort_key )
1385
1384
to_delete = list ()
1385
+ programs = dict ()
1386
1386
for index in range (len (sequence )):
1387
1387
event = sequence [index ]
1388
1388
if isinstance (event , (SetTempo , SetTimeSignature )):
1389
1389
to_delete .append (index )
1390
1390
sequence .specification .add (event )
1391
+ elif isinstance (event , ProgramChange ):
1392
+ to_delete .append (index )
1393
+ programs [(event .track , event .channel )] = event .program
1394
+ elif isinstance (event , ChannelEvent ):
1395
+ try :
1396
+ event .program = programs [(event .track , event .channel )]
1397
+ except KeyError :
1398
+ event .program = Program ()
1399
+ programs [(event .track , event .channel )] = event .program
1391
1400
for index in reversed (to_delete ):
1392
1401
del sequence [index ]
1393
1402
return sequence
@@ -1457,27 +1466,50 @@ def offset(self, time):
1457
1466
event .time += time
1458
1467
self .specification .offset (time )
1459
1468
1469
+ def events (self ):
1470
+ event_list = list ()
1471
+ programs = dict ()
1472
+ for event in self :
1473
+ if isinstance (event , ChannelEvent ):
1474
+ program = programs .get ((event .track , event .channel ), None )
1475
+ if event .program != program :
1476
+ programs [(event .track , event .channel )] = event .program
1477
+ event_list .append (ProgramChange (time = event .time ,
1478
+ program = event .program , track = event .track ,
1479
+ channel = event .channel ))
1480
+ return event_list
1481
+
1460
1482
def sort (self , * , key = None , reverse = False ):
1461
1483
if key == None :
1462
- def meta (event ):
1463
- if isinstance (event , SetTempo ):
1464
- return 0
1465
- elif isinstance (event , SetTimeSignature ):
1466
- return 1
1467
- elif isinstance (event , ProgramChange ):
1468
- return 2
1469
- else :
1470
- return 3
1471
- def track (event ):
1472
- return event .track
1473
- def time (event ):
1474
- return event .time
1475
- super ().sort (key = meta , reverse = reverse )
1476
- super ().sort (key = track , reverse = reverse )
1477
- super ().sort (key = time , reverse = reverse )
1484
+ super ().sort (key = self ._meta_sort_key , reverse = reverse )
1485
+ super ().sort (key = self ._track_sort_key , reverse = reverse )
1486
+ super ().sort (key = self ._time_sort_key , reverse = reverse )
1478
1487
else :
1479
1488
super ().sort (key = key , reverse = False )
1480
1489
1490
+ @staticmethod
1491
+ def _meta_sort_key (event ):
1492
+ if isinstance (event , SetTempo ):
1493
+ return 0
1494
+ elif isinstance (event , SetTimeSignature ):
1495
+ return 1
1496
+ elif isinstance (event , ProgramChange ):
1497
+ return 2
1498
+ else :
1499
+ return 3
1500
+
1501
+ @staticmethod
1502
+ def _track_sort_key (event ):
1503
+ return event .track
1504
+
1505
+ @staticmethod
1506
+ def _time_sort_key (event ):
1507
+ return event .time
1508
+
1509
+ @staticmethod
1510
+ def _cumulative_sort_key (event ):
1511
+ return event .time .cumulative
1512
+
1481
1513
def __bytes__ (self ):
1482
1514
"""Bytes for writing to a MIDI file."""
1483
1515
array = bytearray ()
@@ -1490,6 +1522,8 @@ def __bytes__(self):
1490
1522
array .extend (chunk .raw )
1491
1523
1492
1524
sequence = type (self )(self )
1525
+ sequence .sort ()
1526
+ sequence .extend (sequence .events ())
1493
1527
sequence .extend (self .specification .events (track = 0 ))
1494
1528
sequence .sort ()
1495
1529
for track in range (tracks ):
0 commit comments