【问题标题】:How can I produce real-time audio output from music made with Music21?如何从 Music21 制作的音乐中生成实时音频输出?
【发布时间】:2012-06-14 13:21:04
【问题描述】:

如何从 Music21 制作的音乐中生成实时音频输出。如果做不到这一点,我如何通过开源软件从 Music21 制作的音乐中产生任何音频输出?感谢您的帮助。

【问题讨论】:

  • 你的问题比较模糊。究竟是什么问题?另外,你有read the docs吗?
  • 我不同意——这个问题在被问到时非常集中,解决方案促使工具包本身发生了变化。
  • 为什么关闭?该工具包现在有一个 .show('midi') 选项,这正是 OP 正在寻找的。这个问题没什么含糊的,虽然很简单。

标签: python music21 audio


【解决方案1】:

如您所见,music21 并非设计为音乐播放系统,而是设计为嵌入到其他播放系统中或从系统中调用它们。我们不打算在播放系统上投入太多工作(因为硬件支持,我们是一个小型研究实验室,音乐分析方面的工作仍需完成等),但您的解决方案非常优雅,以至于现在作为music21.midi.realtime 模块包含在所有版本的music21(v1.1 后)中。下面是一个例子,它利用了 music21 动态分配具有不同弯音对象的 midi 通道以模拟微音播放(大多数 midi 播放的主要问题)的能力:

#  Set up a detuned piano 
#  (where each key has a random 
#  but consistent detuning from 30 cents flat to sharp)
#  and play a Bach Chorale on it in real time.

from music21 import *
import random
keyDetune = []
for i in range(0, 127):
    keyDetune.append(random.randint(-30, 30))

b = corpus.parse('bach/bwv66.6')
for n in b.flat.notes:
    n.microtone = keyDetune[n.midi]
sp = midi.realtime.StreamPlayer(b)
sp.play()

StreamPlayer 的 .play() 函数也可以使用 busyFunction 和 busyArgs 和 busyWaitMilliseconds 参数,它们指定一个函数,最多在每个 busyWaitMilliseconds 调用一个函数(如果您的系统较慢,可能会更多)。最后还有一个 endFunction 和 endArgs 将被调用,以防您想设置某种线程播放。 -- Myke Cuthbert(Music21 创作者)

【讨论】:

    【解决方案2】:

    这就是我发现的。这是一个适用于 Windows XP 的 python 脚本。除了music21,它还需要pygame。

    # genPlayM21Score.py Generates and Plays 2 Music21 Scores "on the fly".
    #
    # see way below for source notes
    
    from music21 import *
    
    # we create the music21 Bottom Part, and do this explicitly, one object at a time.
    
    n1 = note.Note('e4')
    n1.duration.type = 'whole'
    n2 = note.Note('d4')
    n2.duration.type = 'whole'
    m1 = stream.Measure()
    m2 = stream.Measure()
    m1.append(n1)
    m2.append(n2)
    partLower = stream.Part()
    partLower.append(m1)
    partLower.append(m2)
    
    # For the music21 Upper Part, we automate the note creation procedure
    
    data1 = [('g4', 'quarter'), ('a4', 'quarter'), ('b4', 'quarter'), ('c#5', 'quarter')]
    data2 = [('d5', 'whole')]
    data = [data1, data2]
    partUpper = stream.Part()
    
    def makeUpperPart(data):
        for mData in data:
            m = stream.Measure()
            for pitchName, durType in mData:
                n = note.Note(pitchName)
                n.duration.type = durType
                m.append(n)
            partUpper.append(m)
    makeUpperPart(data)        
    
    # Now, we can add both Part objects into a music21 Score object.  
    
    sCadence = stream.Score()
    sCadence.insert(0, partUpper)
    sCadence.insert(0, partLower)
    
    # Now, let's play the MIDI of the sCadence Score [from memory, ie no file  write necessary] using pygame
    
    import cStringIO
    
    # for music21 <= v.1.2:
    if hasattr(sCadence, 'midiFile'):
       sCadence_mf = sCadence.midiFile
    else: # for >= v.1.3:
       sCadence_mf = midi.translate.streamToMidiFile(sCadence)
    sCadence_mStr = sCadence_mf.writestr()
    sCadence_mStrFile = cStringIO.StringIO(sCadence_mStr)
    
    import pygame
    
    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)
    
    # optional volume 0 to 1.0
    pygame.mixer.music.set_volume(0.8)
    
    def play_music(music_file):
        """
        stream music with mixer.music module in blocking manner
        this will stream the sound from disk while playing
        """
        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
            clock.tick(30)
    
    # play the midi file we just saved
    play_music(sCadence_mStrFile)
    
    #============================
    
    # now let's make a new music21 Score by reversing the upperPart notes
    data1.reverse()
    data2 = [('d5', 'whole')]
    data = [data1, data2]
    partUpper = stream.Part()
    makeUpperPart(data)        
    sCadence2 = stream.Score()
    sCadence2.insert(0, partUpper)
    sCadence2.insert(0, partLower)
    
    # now let's play the new Score
    sCadence2_mf = sCadence2.midiFile
    sCadence2_mStr = sCadence2_mf.writestr()
    sCadence2_mStrFile = cStringIO.StringIO(sCadence2_mStr)
    play_music(sCadence2_mStrFile)
    
    
    
    ## SOURCE NOTES
    ## There are 3 sources for this mashup:
    
    # 1. Source for the Music21 Score Creation http://web.mit.edu/music21/doc/html/quickStart.html#creating-notes-measures-parts-and-scores
    
    # 2.  Source for the Music21 MidiFile Class Behaviour http://mit.edu/music21/doc/html/moduleMidiBase.html?highlight=midifile#music21.midi.base.MidiFile
    
    # 3.  Source for the pygame player: http://www.daniweb.com/software-development/python/code/216979/embed-and-play-midi-music-in-your-code-python
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-11
      相关资源
      最近更新 更多