mms-lib 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {mms_lib-0.3.0 → mms_lib-0.3.2}/PKG-INFO +1 -1
  2. {mms_lib-0.3.0 → mms_lib-0.3.2}/pyproject.toml +1 -1
  3. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/__init__.py +1 -1
  4. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/assets/text/features.json +0 -1
  5. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/assets/text/mapping.json +30 -30
  6. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/assets/text/profile.json +32 -32
  7. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/core.py +3 -3
  8. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/dataclass.py +30 -13
  9. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/midi_reader.py +30 -11
  10. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/nbs_reader.py +10 -11
  11. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/tools.py +5 -1
  12. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms_lib.egg-info/PKG-INFO +1 -1
  13. {mms_lib-0.3.0 → mms_lib-0.3.2}/LICENSE +0 -0
  14. {mms_lib-0.3.0 → mms_lib-0.3.2}/README.md +0 -0
  15. {mms_lib-0.3.0 → mms_lib-0.3.2}/setup.cfg +0 -0
  16. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/assets/text/settings.json +0 -0
  17. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/cli.py +0 -0
  18. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/evaltools.py +0 -0
  19. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/__init__.py +0 -0
  20. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/frozen.py +0 -0
  21. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/__init__.py +0 -0
  22. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/checks.py +0 -0
  23. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/decode.py +0 -0
  24. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/encode.py +0 -0
  25. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/messages.py +0 -0
  26. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/specs.py +0 -0
  27. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/messages/strings.py +0 -0
  28. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/midifiles/__init__.py +0 -0
  29. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/midifiles/meta.py +0 -0
  30. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/midifiles/midifiles.py +0 -0
  31. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/midifiles/tracks.py +0 -0
  32. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/midifiles/units.py +0 -0
  33. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/parser.py +0 -0
  34. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/tokenizer.py +0 -0
  35. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/mido/version.py +0 -0
  36. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/pynbs/__init__.py +0 -0
  37. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms/pynbs/file.py +0 -0
  38. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms_lib.egg-info/SOURCES.txt +0 -0
  39. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms_lib.egg-info/dependency_links.txt +0 -0
  40. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms_lib.egg-info/entry_points.txt +0 -0
  41. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms_lib.egg-info/requires.txt +0 -0
  42. {mms_lib-0.3.0 → mms_lib-0.3.2}/src/mms_lib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mms-lib
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Extract from MIDI-MCSTRUCTURE NEXT Project
5
5
  Requires-Python: >=3.14
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mms-lib"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  description = "Extract from MIDI-MCSTRUCTURE NEXT Project"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -2,4 +2,4 @@ from .core import init, read_midi, convertor, profile
2
2
  from .dataclass import Settings, Note, Lyrics
3
3
 
4
4
  __all__ = ["init", "read_midi", "convertor", "profile", "Note", "Lyrics", "Settings"]
5
- __version__ = "0.3.0"
5
+ __version__ = "0.3.2"
@@ -51,7 +51,6 @@
51
51
  "109": ["linear_note"],
52
52
  "110": ["linear_note"],
53
53
  "124": ["linear_note"],
54
- "612": ["linear_note"],
55
54
  "percussion": {
56
55
  "undefined": []
57
56
  }
@@ -27,11 +27,11 @@
27
27
  "27": "guitar",
28
28
  "28": "guitar",
29
29
  "29": "guitar",
30
- "30": "bass",
31
- "31": "bass",
30
+ "30": "guitar",
31
+ "31": "guitar",
32
32
  "32": "bass",
33
- "33": "guitar",
34
- "34": "guitar",
33
+ "33": "bass",
34
+ "34": "bass",
35
35
  "35": "bass",
36
36
  "36": "bass",
37
37
  "37": "bass",
@@ -43,12 +43,12 @@
43
43
  "43": "didgeridoo",
44
44
  "45": "pling",
45
45
  "46": "harp",
46
- "47": "iron_xylophone",
46
+ "47": "base_drum",
47
47
  "48": "flute",
48
48
  "49": "flute",
49
49
  "50": "flute",
50
50
  "51": "flute",
51
- "52": "didgeridoo",
51
+ "52": "flute",
52
52
  "53": "flute",
53
53
  "54": "flute",
54
54
  "55": "orchestra_hit",
@@ -57,12 +57,12 @@
57
57
  "58": "tuba",
58
58
  "59": "trumpet",
59
59
  "60": "french_horn",
60
- "61": "flute",
61
- "62": "flute",
62
- "63": "flute",
60
+ "61": "trumpet",
61
+ "62": "trumpet",
62
+ "63": "trumpet",
63
63
  "64": "flute",
64
- "65": "guitar",
65
- "66": "bass",
64
+ "65": "flute",
65
+ "66": "flute",
66
66
  "67": "didgeridoo",
67
67
  "68": "flute",
68
68
  "69": "flute",
@@ -73,7 +73,7 @@
73
73
  "74": "flute",
74
74
  "75": "flute",
75
75
  "76": "flute",
76
- "77": "banjo",
76
+ "77": "flute",
77
77
  "78": "flute",
78
78
  "79": "flute",
79
79
  "80": "bit",
@@ -83,11 +83,11 @@
83
83
  "84": "bit",
84
84
  "85": "flute",
85
85
  "86": "flute",
86
- "87": "orchestra_hit",
87
- "88": "banjo",
86
+ "87": "bit",
87
+ "88": "flute",
88
88
  "89": "flute",
89
89
  "90": "bit",
90
- "91": "orchestra_hit",
90
+ "91": "flute",
91
91
  "92": "didgeridoo",
92
92
  "93": "iron_xylophone",
93
93
  "94": "bit",
@@ -99,9 +99,10 @@
99
99
  "109": "flute",
100
100
  "110": "flute",
101
101
  "111": "flute",
102
- "112": "cow_bell",
103
- "114": "hat",
104
- "115": "xylophone",
102
+ "112": "bell",
103
+ "113": "cow_bell",
104
+ "114": "iron_xylophone",
105
+ "115": "hat",
105
106
  "116": "base_drum",
106
107
  "117": "snare",
107
108
  "118": "snare",
@@ -109,29 +110,28 @@
109
110
  "123": "parrot",
110
111
  "124": "telephone_ring",
111
112
  "125": "helicopter",
112
- "126": "hat",
113
+ "126": "snare",
113
114
  "127": "gun",
114
- "612": "trumpet",
115
115
  "percussion": {
116
116
  "undefined": "cymbal",
117
117
  "31": "hat",
118
- "33": "snare",
119
- "34": "hat",
118
+ "33": "hat",
119
+ "34": "bell",
120
120
  "35": "base_drum",
121
- "36": "snare",
121
+ "36": "base_drum",
122
122
  "37": "hat",
123
- "38": "hat",
124
- "39": "hat",
125
- "40": "hat",
123
+ "38": "snare",
124
+ "39": "snare",
125
+ "40": "snare",
126
126
  "41": "base_drum",
127
127
  "42": "closed_cymbal",
128
- "43": "hat",
128
+ "43": "base_drum",
129
129
  "44": "pedal_cymbal",
130
130
  "45": "base_drum",
131
131
  "46": "open_cymbal",
132
- "47": "snare",
133
- "48": "hat",
134
- "50": "hat",
132
+ "47": "base_drum",
133
+ "48": "base_drum",
134
+ "50": "base_drum",
135
135
  "56": "cow_bell",
136
136
  "69": "cabasa",
137
137
  "82": "shaker",
@@ -77,22 +77,22 @@
77
77
  ["note.bd", 1.5, 0, 0]
78
78
  ],
79
79
  "cymbal": [
80
- ["random.fizz", 1.0, 19, 0]
80
+ ["dig.sand", 1.0, 19, 0]
81
81
  ],
82
82
  "open_cymbal": [
83
- ["random.fizz", 1.5, 19, 0]
83
+ ["dig.sand", 1.5, 19, 0]
84
84
  ],
85
85
  "pedal_cymbal": [
86
- ["random.fizz", 1.5, 31, 0]
86
+ ["dig.sand", 1.5, 31, 0]
87
87
  ],
88
88
  "closed_cymbal": [
89
- ["random.fizz", 1.5, 38, 0]
89
+ ["dig.sand", 1.5, 38, 0]
90
90
  ],
91
91
  "cabasa": [
92
- ["random.fizz", 1.2, 19, 0]
92
+ ["dig.sand", 1.2, 19, 0]
93
93
  ],
94
94
  "shaker": [
95
- ["random.fizz", 1.2, 31, 0]
95
+ ["dig.sand", 1.2, 31, 0]
96
96
  ],
97
97
  "parrot": [
98
98
  ["mob.parrot.idle", 1.0, 0, 0]
@@ -122,16 +122,16 @@
122
122
  ["note.didgeridoo", 0.8, 0, 0]
123
123
  ],
124
124
  "trumpet": [
125
- ["note.trumpet", 0.7, 0, 0]
125
+ ["note.trumpet", 0.5, 0, 0]
126
126
  ],
127
127
  "french_horn": [
128
- ["note.trumpet_exposed", 0.7, 0, 0]
128
+ ["note.trumpet_exposed", 0.5, 0, 0]
129
129
  ],
130
130
  "trombone": [
131
- ["note.trumpet_weathered", 0.7, 0, 0]
131
+ ["note.trumpet_weathered", 0.5, 0, 0]
132
132
  ],
133
133
  "tuba": [
134
- ["note.trumpet_oxidized", 0.7, 0, 0]
134
+ ["note.trumpet_oxidized", 0.5, 0, 0]
135
135
  ],
136
136
  "orchestra_hit": [
137
137
  ["note.bass", 0.4, 0, 0],
@@ -235,22 +235,22 @@
235
235
  ["block.note_block.basedrum", 1.5, 0, 0]
236
236
  ],
237
237
  "cymbal": [
238
- ["block.fire.extinguish", 1.0, 19, 0]
238
+ ["block.sand.break", 1.0, 19, 0]
239
239
  ],
240
240
  "open_cymbal": [
241
- ["block.fire.extinguish", 1.5, 19, 0]
241
+ ["block.sand.break", 1.5, 19, 0]
242
242
  ],
243
243
  "pedal_cymbal": [
244
- ["block.fire.extinguish", 1.5, 31, 0]
244
+ ["block.sand.break", 1.5, 31, 0]
245
245
  ],
246
246
  "closed_cymbal": [
247
- ["block.fire.extinguish", 1.5, 38, 0]
247
+ ["block.sand.break", 1.5, 38, 0]
248
248
  ],
249
249
  "cabasa": [
250
- ["block.fire.extinguish", 1.2, 19, 0]
250
+ ["block.sand.break", 1.2, 19, 0]
251
251
  ],
252
252
  "shaker": [
253
- ["block.fire.extinguish", 1.2, 31, 0]
253
+ ["block.sand.break", 1.2, 31, 0]
254
254
  ],
255
255
  "parrot": [
256
256
  ["entity.parrot.ambient", 1.0, 0, 0]
@@ -280,16 +280,16 @@
280
280
  ["block.note_block.didgeridoo", 0.8, 0, 0]
281
281
  ],
282
282
  "trumpet": [
283
- ["block.note_block.trumpet", 0.7, 0, 0]
283
+ ["block.note_block.trumpet", 0.5, 0, 0]
284
284
  ],
285
285
  "french_horn": [
286
- ["block.note_block.trumpet_exposed", 0.7, 0, 0]
286
+ ["block.note_block.trumpet_exposed", 0.5, 0, 0]
287
287
  ],
288
288
  "trombone": [
289
- ["block.note_block.trumpet_weathered", 0.7, 0, 0]
289
+ ["block.note_block.trumpet_weathered", 0.5, 0, 0]
290
290
  ],
291
291
  "tuba": [
292
- ["block.note_block.trumpet_oxidized", 0.7, 0, 0]
292
+ ["block.note_block.trumpet_oxidized", 0.5, 0, 0]
293
293
  ],
294
294
  "orchestra_hit": [
295
295
  ["block.note_block.bass", 0.4, 0, 0],
@@ -381,22 +381,22 @@
381
381
  ["note.bd", 1.5, 0, 0]
382
382
  ],
383
383
  "cymbal": [
384
- ["random.fizz", 1.0, 19, 0]
384
+ ["dig.sand", 1.0, 19, 0]
385
385
  ],
386
386
  "open_cymbal": [
387
- ["random.fizz", 1.5, 19, 0]
387
+ ["dig.sand", 1.5, 19, 0]
388
388
  ],
389
389
  "pedal_cymbal": [
390
- ["random.fizz", 1.5, 31, 0]
390
+ ["dig.sand", 1.5, 31, 0]
391
391
  ],
392
392
  "closed_cymbal": [
393
- ["random.fizz", 1.5, 38, 0]
393
+ ["dig.sand", 1.5, 38, 0]
394
394
  ],
395
395
  "cabasa": [
396
- ["random.fizz", 1.2, 19, 0]
396
+ ["dig.sand", 1.2, 19, 0]
397
397
  ],
398
398
  "shaker": [
399
- ["random.fizz", 1.2, 31, 0]
399
+ ["dig.sand", 1.2, 31, 0]
400
400
  ],
401
401
  "parrot": [
402
402
  ["mob.parrot.idle", 1.0, 0, 0]
@@ -501,22 +501,22 @@
501
501
  ["block.note.basedrum", 1.5, 0, 0]
502
502
  ],
503
503
  "cymbal": [
504
- ["block.fire.extinguish", 1.0, 19, 0]
504
+ ["block.sand.break", 1.0, 19, 0]
505
505
  ],
506
506
  "open_cymbal": [
507
- ["block.fire.extinguish", 1.5, 19, 0]
507
+ ["block.sand.break", 1.5, 19, 0]
508
508
  ],
509
509
  "pedal_cymbal": [
510
- ["block.fire.extinguish", 1.5, 31, 0]
510
+ ["block.sand.break", 1.5, 31, 0]
511
511
  ],
512
512
  "closed_cymbal": [
513
- ["block.fire.extinguish", 1.5, 38, 0]
513
+ ["block.sand.break", 1.5, 38, 0]
514
514
  ],
515
515
  "cabasa": [
516
- ["block.fire.extinguish", 1.2, 19, 0]
516
+ ["block.sand.break", 1.2, 19, 0]
517
517
  ],
518
518
  "shaker": [
519
- ["block.fire.extinguish", 1.2, 31, 0]
519
+ ["block.sand.break", 1.2, 31, 0]
520
520
  ],
521
521
  "parrot": [
522
522
  ["entity.parrot.ambient", 1.0, 0, 0]
@@ -172,7 +172,7 @@ def get_notes(midi_file: MIDIReader, platform_profile: dict, tempo: float | int)
172
172
  if data.percussion:
173
173
  program = platform_profile["sound_list"].get(profile.mapping.get_p(data.program), platform_profile["sound_list"][profile.mapping.p_mapping["undefined"]])
174
174
 
175
- if "linear_note" in profile.features["percussion"].get(str(data.source_program), profile.features["percussion"]["undefined"]):
175
+ if "linear_note" in profile.features["percussion"].get(str(data.program), profile.features["percussion"]["undefined"]):
176
176
  linear_note = True
177
177
  else:
178
178
  if data.program == -1:
@@ -180,13 +180,13 @@ def get_notes(midi_file: MIDIReader, platform_profile: dict, tempo: float | int)
180
180
  else:
181
181
  program = platform_profile["sound_list"].get(profile.mapping.get(data.program), platform_profile["sound_list"][profile.mapping.mapping["undefined"]])
182
182
 
183
- if "linear_note" in profile.features.get(str(data.source_program), profile.features["undefined"]):
183
+ if "linear_note" in profile.features.get(str(data.program), profile.features["undefined"]):
184
184
  linear_note = True
185
185
 
186
186
  if program is None: continue
187
187
 
188
188
  delay_time = 0
189
- while data.time + delay_time < time:
189
+ while data.time + delay_time <= time:
190
190
  # 一个音符可以对应多个我的世界乐器,因此这里遍历一下从配置文件中获取的数据
191
191
  for note in program:
192
192
  # 累加配置文件中我的世界乐器之间的时间间隔
@@ -227,7 +227,6 @@ class Lyrics:
227
227
 
228
228
  class NoteData:
229
229
  __slots__ = (
230
- "source_program",
231
230
  "percussion",
232
231
  "velocity",
233
232
  "panning",
@@ -237,15 +236,14 @@ class NoteData:
237
236
  "type"
238
237
  )
239
238
 
240
- def __init__(self, time: float, pitch: float, program: tuple[int, int], panning: tuple[float, float], velocity: float):
239
+ def __init__(self, time: float, pitch: float, program: int, panning: tuple[float, float], velocity: float):
241
240
  self.type = "note"
242
241
  self.time = time
243
242
  self.pitch = pitch
244
- self.program = program[0]
243
+ self.program = program
245
244
  self.panning = panning
246
245
  self.velocity = velocity
247
246
  self.percussion = False
248
- self.source_program = program[1]
249
247
 
250
248
  class LyricsData:
251
249
  __slots__ = (
@@ -380,29 +378,48 @@ class LyricsList:
380
378
  class Stack:
381
379
  __slots__ = (
382
380
  "__data",
381
+ "__p_data"
383
382
  )
384
383
 
385
384
  def __init__(self):
386
385
  self.__data: dict[int, dict[float, list[NoteData]]] = {}
386
+ self.__p_data: dict[int, dict[float, list[NoteData]]] = {}
387
387
 
388
388
  def put(self, channel: int, data: NoteData):
389
- data.percussion = channel == 9
389
+ if channel == 9:
390
+ base = self.__p_data
391
+ note_id = data.program
392
+ data.percussion = True
393
+ else:
394
+ base = self.__data
395
+ note_id = data.pitch
396
+ data.percussion = False
397
+
398
+ if channel not in base:
399
+ base[channel] = {note_id: [data]}
400
+ elif note_id not in base[channel]:
401
+ base[channel][note_id] = [data]
402
+ else:
403
+ base[channel][note_id].append(data)
390
404
 
391
- if channel not in self.__data:
392
- self.__data[channel] = {data.pitch: [data]}
393
- elif data.pitch not in self.__data[channel]:
394
- self.__data[channel][data.pitch] = [data]
405
+ def get(self, channel: int, note_id: int) -> NoteData | None:
406
+ if channel == 9:
407
+ base = self.__p_data
395
408
  else:
396
- self.__data[channel][data.pitch].append(data)
409
+ base = self.__data
397
410
 
398
- def get(self, channel: int, pitch: int) -> NoteData | None:
399
- if pitch in self.__data[channel] and self.__data[channel][pitch]:
400
- return self.__data[channel][pitch].pop()
411
+ if note_id in base.get(channel, {}) and base[channel][note_id]:
412
+ return base[channel][note_id].pop()
401
413
  else:
402
414
  return None
403
415
 
404
416
  def __iter__(self):
405
417
  for channel in self.__data.values():
418
+ for notes in channel.values():
419
+ for note in notes:
420
+ yield note
421
+
422
+ for channel in self.__p_data.values():
406
423
  for notes in channel.values():
407
424
  for note in notes:
408
425
  yield note
@@ -134,9 +134,6 @@ class MIDIReader:
134
134
  def get_time_accuracy(self, time_per_tick: float) -> float:
135
135
  return sum(map(lambda i: (round_int(i / time_per_tick) - i / time_per_tick) ** 2, self._scan_time_nodes()))
136
136
 
137
- def override_mapping(self, mapping: dict[int, dict[int, int]]) -> None:
138
- self.__instruments_mapping = mapping
139
-
140
137
  def __iter__(self):
141
138
  stack = Stack()
142
139
  tempo_info = TempoList(self.__midi_file.ticks_per_beat)
@@ -154,14 +151,12 @@ class MIDIReader:
154
151
  # 判断该事件是否有通道数据,如果有并且通道没有初始化数据就初始化该通道
155
152
  if hasattr(message, "channel"):
156
153
  channel = message.channel
157
- mapping: dict[int, int] = self.__instruments_mapping.get(channel, {})
158
154
  if channel not in channel_info:
159
155
  channel_info[channel] = {
160
156
  "program": InfoList(-1),
161
157
  "volume": InfoList(1),
162
158
  "panning": InfoList((0, 1))}
163
159
  else:
164
- mapping = {}
165
160
  channel = -1
166
161
  # 获取tempo信息
167
162
  if message.type == "set_tempo":
@@ -189,7 +184,7 @@ class MIDIReader:
189
184
  # 获取歌词数据
190
185
  data = LyricsData(message.text)
191
186
  # 获取音符信息
192
- elif message.type == "note_on" and message.velocity != 0:
187
+ elif message.type == "note_on" and message.velocity > 0:
193
188
  # 对音符力度(音量)进行归一化处理
194
189
  note_velocity = message.velocity / 127
195
190
  # 音符音量再乘以音符所在的通道的音量
@@ -201,17 +196,41 @@ class MIDIReader:
201
196
  # 打击乐器保持原声
202
197
  note_pitch = 66
203
198
  note_program = message.note
199
+
200
+ data = stack.get(channel, note_program)
201
+
202
+ stack.put(
203
+ channel,
204
+ NoteData(
205
+ tempo_info.compute_time(time),
206
+ note_pitch,
207
+ note_program,
208
+ note_panning,
209
+ note_velocity
210
+ )
211
+ )
204
212
  else:
205
213
  note_pitch = message.note
206
214
  note_program = channel_info[channel]["program"].match_info(time)
207
215
 
208
- # 打包数据
209
- stack.put(channel, NoteData(tempo_info.compute_time(time), note_pitch, (mapping.get(note_program, note_program), note_program), note_panning, note_velocity))
210
-
211
- elif message.type == "note_off" or (message.type == "note_on" and message.velocity == 0):
216
+ if note_data := stack.get(channel, note_pitch):
217
+ data = note_data
218
+
219
+ stack.put(
220
+ channel,
221
+ NoteData(
222
+ tempo_info.compute_time(time),
223
+ note_pitch,
224
+ note_program,
225
+ note_panning,
226
+ note_velocity
227
+ )
228
+ )
229
+
230
+ elif message.type == "note_off" or message.type == "note_on":
212
231
  data = stack.get(channel, message.note)
213
232
 
214
233
  # 将音符时间转为绝对时间并返回结果,时间单位为毫秒
215
234
  if data is not None: yield tempo_info.compute_time(time), data
216
235
 
217
- for data in stack: yield data.time + 0.00001, data
236
+ for data in stack: yield data.time, data
@@ -6,21 +6,21 @@ from .dataclass import NoteData
6
6
 
7
7
  NBS_TO_GM_MAPPING = {
8
8
  0: 0,
9
- 1: 43,
9
+ 1: 32,
10
10
  2: 116,
11
11
  3: 118,
12
12
  4: 115,
13
13
  5: 24,
14
14
  6: 73,
15
- 7: 14,
16
- 8: 8,
15
+ 7: 9,
16
+ 8: 14,
17
17
  9: 13,
18
- 10: 9,
18
+ 10: 11,
19
19
  11: 113,
20
- 12: 111,
20
+ 12: 43,
21
21
  13: 80,
22
22
  14: 105,
23
- 15: 98,
23
+ 15: 1,
24
24
  }
25
25
 
26
26
  class NBSReader:
@@ -52,12 +52,11 @@ class NBSReader:
52
52
  radian = math.radians((panning + 100) * 0.9)
53
53
 
54
54
  note_data = NoteData(
55
- tick * 50,
55
+ current_time := tick * (1000 / self.__nbs_file.header.tempo),
56
56
  note.key + 21 + note.pitch / 100,
57
- (NBS_TO_GM_MAPPING.get(note.instrument, 0), ) * 2,
57
+ NBS_TO_GM_MAPPING.get(note.instrument, 0),
58
58
  (round_45(math.cos(radian), 2), round_45(math.sin(radian), 2)),
59
- note.velocity * volume_info[note.layer]
59
+ note.velocity * volume_info[note.layer] / 10000
60
60
  )
61
61
 
62
- yield tick * 50 + 0.00001, note_data
63
-
62
+ yield current_time, note_data
@@ -26,4 +26,8 @@ def is_number(text: str) -> bool:
26
26
  return all(text[i] in "0123456789" or (text[i] == "." and 1 < i + 1 < length) for i in range(length)) and text.count(".") <= 1
27
27
 
28
28
  def is_midi(data: bytes) -> bool:
29
- return data[:4] == b"MThd"
29
+ return data[:4] == b"MThd"
30
+
31
+ def replace_item(d: dict, k, v):
32
+ old_v, d[k] = d[k], v
33
+ return old_v
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mms-lib
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Extract from MIDI-MCSTRUCTURE NEXT Project
5
5
  Requires-Python: >=3.14
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes