मैं मिडी मिलीसेकेंड के टिक्स/डेल्टा समय और पहले से ही कुछ उपयोगी साधन पाया है परिवर्तित करने के लिए कोशिश कर रहा हूँ:मिडी टिक्स को मिलीसेकंड में सही तरीके से कैसे परिवर्तित करें?
- MIDI Delta Time Ticks to Seconds
- How to convert midi timeline into the actual timeline that should be played
- MIDI Time Code spec
- MTC
समस्या यह नहीं है कि मुझे नहीं लगता कि मैं इस जानकारी का सही ढंग से उपयोग कर रहा हूं। this test MIDI file से
[ 1 min 60 sec 1 beat Z clocks ]
| ------- * ------ * -------- * -------- | = seconds
[ X beats 1 min Y clocks 1 ]
मेटाडेटा का उपयोग: मैं सूत्र Nik विस्तार को लागू करने की कोशिश की है
<meta message set_tempo tempo=576923 time=0>
<meta message key_signature key='Ab' time=0>
<meta message time_signature numerator=4 denominator=4 clocks_per_click=24 notated_32nd_notes_per_beat=8 time=0>
तो जैसा:
self.toSeconds = 60.0 * self.t[0][2].clocks_per_click/(self.t[0][0].tempo * self.t[0][2].denominator) * 10
यह शुरू में ठीक लग रहा है, लेकिन फिर ऐसा लगता है भटकना। यहाँ एक बुनियादी runnable Mido और pygame का उपयोग कर उदाहरण है (यह मानते हुए pygame वापस निभाता है सही ढंग से):
import threading
import pygame
from pygame.locals import *
from mido import MidiFile,MetaMessage
music_file = "Bee_Gees_-_Stayin_Alive-Voice.mid"
#audio setup
freq = 44100 # audio CD quality
bitsize = -16 # unsigned 16 bit
channels = 2 # 1 is mono, 2 is stereo
buffer = 1024 # number of samples
pygame.mixer.init(freq, bitsize, channels, buffer)
pygame.mixer.music.set_volume(0.8)
class MIDIPlayer(threading.Thread):
def __init__(self,music_file):
try:
#MIDI parsing
self.mid = MidiFile(music_file)
self.t = self.mid.tracks
for i, track in enumerate(self.mid.tracks):
print('Track {}: {}'.format(i, track.name))
for message in track:
if isinstance(message, MetaMessage):
if message.type == 'time_signature' or message.type == 'set_tempo' or message.type == 'key_signature':
print message
self.t0 = self.t[0][3:len(self.t[0])-1]
self.t0l = len(self.t0)
self.toSeconds = 60.0 * self.t[0][2].clocks_per_click/(self.t[0][0].tempo * self.t[0][2].denominator) * 10
print "self.toSeconds",self.toSeconds
#timing setup
self.event_id = 0
self.now = pygame.time.get_ticks()
self.play_music(music_file)
except KeyboardInterrupt:
pygame.mixer.music.fadeout(1000)
pygame.mixer.music.stop()
raise SystemExit
def play_music(self,music_file):
clock = pygame.time.Clock()
try:
pygame.mixer.music.load(music_file)
print "Music file %s loaded!" % music_file
except pygame.error:
print "File %s not found! (%s)" % (music_file, pygame.get_error())
return
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
# check if playback has finished
millis = pygame.time.get_ticks()
deltaMillis = self.t0[self.event_id].time * self.toSeconds * 1000
# print millis,deltaMillis
if millis - self.now >= deltaMillis:
print self.t0[self.event_id].text
self.event_id = (self.event_id + 1) % self.t0l
self.now = millis
clock.tick(30)
MIDIPlayer(music_file)
क्या उपरोक्त कोड करना चाहिए मिडी फ़ाइल के आधार पर सही समय पर सही गीत मुद्रित है, फिर भी यह drifts अधिक समय तक।
MIDI डेल्टा समय को सेकंड/मिलीसेकंड में परिवर्तित करने का सही तरीका क्या है?
अद्यतन
सीएल के सहायक जवाब पर मैं हैडर से ticks_per_beat उपयोग करने के लिए कोड को नवीनीकृत किया है के आधार पर। के बाद से वहाँ एक भी set_tempo
मेटा संदेश है, मैं भर में इस मूल्य का उपयोग कर रहा:
import threading
import pygame
from pygame.locals import *
from mido import MidiFile,MetaMessage
music_file = "Bee_Gees_-_Stayin_Alive-Voice.mid"
#audio setup
freq = 44100 # audio CD quality
bitsize = -16 # unsigned 16 bit
channels = 2 # 1 is mono, 2 is stereo
buffer = 1024 # number of samples
pygame.mixer.init(freq, bitsize, channels, buffer)
pygame.mixer.music.set_volume(0.8)
class MIDIPlayer(threading.Thread):
def __init__(self,music_file):
try:
#MIDI parsing
self.mid = MidiFile(music_file)
self.t = self.mid.tracks
for i, track in enumerate(self.mid.tracks):
print('Track {}: {}'.format(i, track.name))
for message in track:
# print message
if isinstance(message, MetaMessage):
if message.type == 'time_signature' or message.type == 'set_tempo' or message.type == 'key_signature' or message.type == 'ticks_per_beat':
print message
self.t0 = self.t[0][3:len(self.t[0])-1]
self.t0l = len(self.t0)
self.toSeconds = 60.0 * self.t[0][2].clocks_per_click/(self.t[0][0].tempo * self.t[0][2].denominator) * 10
print "self.toSeconds",self.toSeconds
# append delta delays in milliseconds
self.delays = []
tempo = self.t[0][0].tempo
ticks_per_beat = self.mid.ticks_per_beat
last_event_ticks = 0
microseconds = 0
for event in self.t0:
delta_ticks = event.time - last_event_ticks
last_event_ticks = event.time
delta_microseconds = tempo * delta_ticks/ticks_per_beat
microseconds += delta_microseconds
print event.text,microseconds/1000000.0
self.delays.append(microseconds/1000)
#timing setup
self.event_id = 0
self.now = pygame.time.get_ticks()
self.play_music(music_file)
except KeyboardInterrupt:
pygame.mixer.music.fadeout(1000)
pygame.mixer.music.stop()
raise SystemExit
def play_music(self,music_file):
clock = pygame.time.Clock()
try:
pygame.mixer.music.load(music_file)
print "Music file %s loaded!" % music_file
except pygame.error:
print "File %s not found! (%s)" % (music_file, pygame.get_error())
return
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
# check if playback has finished
millis = pygame.time.get_ticks()
# deltaMillis = self.t0[self.event_id].time * self.toSeconds * 1000
deltaMillis = self.delays[self.event_id]
# print millis,deltaMillis
if millis - self.now >= deltaMillis:
print self.t0[self.event_id].text
self.event_id = (self.event_id + 1) % self.t0l
self.now = millis
clock.tick(30)
MIDIPlayer(music_file)
संदेशों मैं समय मिलीसेकंड में बदल जाती के आधार पर प्रिंट से समय ज्यादा बेहतर लग रहा है। हालांकि, कुछ सेकंड के बाद भी यह बहती है।
क्या मैं मिडी टिक्स को मिलीसेकंड में सही ढंग से परिवर्तित कर रहा हूं और लूप के दौरान अपडेट में पास मिलीसेकंड का ट्रैक रख सकता हूं?
इस तरह रूपांतरण किया जाता है: self.delays = []
tempo = self.t[0][0].tempo
ticks_per_beat = self.mid.ticks_per_beat
last_event_ticks = 0
microseconds = 0
for event in self.t0:
delta_ticks = event.time - last_event_ticks
last_event_ticks = event.time
delta_microseconds = tempo * delta_ticks/ticks_per_beat
microseconds += delta_microseconds
print event.text,microseconds/1000000.0
self.delays.append(microseconds/1000)
और यह कैसे की जांच अगर एक 'क्यू' समय के रूप में सामना करना पड़ा था गुजरता है:
millis = pygame.time.get_ticks()
deltaMillis = self.delays[self.event_id]
if millis - self.now >= deltaMillis:
print self.t0[self.event_id].text
self.event_id = (self.event_id + 1) % self.t0l
self.now = millis
clock.tick(30)
मैं मुझे यकीन नहीं है कि क्या यह कार्यान्वयन एमआईडीआई डेल्टा टिक्स को मिलीसेकंड में गलत तरीके से परिवर्तित करता है, गलत तरीके से जांच करें कि मिलीसेकंद आधारित देरी पास या दोनों हैं या नहीं।
उत्तर के लिए धन्यवाद। थोड़ा सा कोशिश करेंगे। सिर्फ दो बार जांचना चाहता था: '' 'tocks_per_click'''' 'ticks_per_beat''' जैसा ही है? (मुझे मेटा संदेशों में '' ticks_per_beat''' नहीं मिल रहा है) –
घटनाओं के समय को निर्धारित करने के लिए समय हस्ताक्षर घटनाएं * आवश्यक नहीं हैं; वे केवल नोटेशन के लिए उपयोगी हैं। मिडो में, संपत्ति जो प्रति बीट टिक निर्दिष्ट करती है उसे 'ticks_per_beat' कहा जाता है। –
क्षमा करें, मुझे नहीं लगता कि मैंने बहुत अच्छी तरह से समझाया है। आप परीक्षण MIDI फ़ाइल के MIDI संदेशों को देख सकते हैं जो मैं टेक्स्ट [यहां] (http://lifesine.eu/so/Bee_Gees_-_Stayin_Alive-Voice.txt) के रूप में उपयोग कर रहा हूं। ऐसा लगता है कि '' ticks_per_beat''' नामक कोई संदेश नहीं है। क्या एमआईडीआई फाइल के लिए यह जानकारी याद आ सकती है? यदि हां, तो क्या किया जा सकता है? धन्यवाद (+1) –