Использование AKSampleDescriptor - PullRequest
       7

Использование AKSampleDescriptor

0 голосов
/ 27 октября 2018

Использование AKSamplerDescriptor

Я использую адаптированный пример AKSampler, в котором я пытаюсь использовать вывод sforzando Fluid.sf3 melodicSounds. Sforzando создает файлы .sfz для каждого инструмента, но все они указывают на глобальный образец на огромный файл .wav.

Во всех файлах instrument.sfz есть описание смещения и конечной точки для используемой части волнового файла.

При загрузке файла .sfz происходит сбой из-за проблем с памятью. Похоже, что для каждого определенного региона в файле .sfz снова загружается полный файл .wav (140 мБ).

Скорее всего, при загрузке файла примера с помощью AKSampleDescriptor, как это сделано в примере AKSampler, будут игнорироваться смещение и конечная точка (AKSampleDescriptor.startPoint и AKSampleDescriptor.endPoint) при перезагрузке полного файла .wav.

Есть ли способ загрузить только необходимую начальную часть детали из файла образца, потому что полный файл содержит все данные образца для всех инструментов (я знаю и использую полифонию, которая извлекает только один инструмент за раз и отлично работает, но это для другого использования)

Или, и это мне кажется лучшим, просто загрузите файл один раз, а затем дескрипторы образца указывают на данные в памяти

1 Ответ

0 голосов
/ 30 октября 2018

Хорошие предложения, Роб.Я только что столкнулся с этой проблемой одного гиганта-WAV, никогда не видел ее прежде.Я также использовал Sforzando для конвертации.Я посмотрю на добавление необходимых возможностей в AKSampler.В то же время может быть проще написать программу, которая будет разрезать один WAV-файл на более мелкие части и соответствующим образом корректировать SFZ.

Вот код Python 2.7 для этого, который я успешно использовал спреобразованный в Sforzando sf2 soundfont.Это может потребовать изменений, чтобы работать на вас - существует огромная изменчивость среди файлов sfz - но, по крайней мере, это может помочь вам начать работу.Этот код требует библиотеки PyDub для управления звуком WAV.

import os
import re
from pydub import AudioSegment

def stripComments(text):
    def replacer(match):
        s = match.group(0)
        if s.startswith('/'):
            return " " # note: a space and not an empty string
        else:
            return s
    pattern = re.compile(
        r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
        re.DOTALL | re.MULTILINE
    )
    return re.sub(pattern, replacer, text)

def updateSplitList(splitList, regionLabels, values):
    if len(values) > 3:
        start = int(values['offset'])
        length = int(values['end']) - start
        name = regionLabels.pop(0)
        splitList.add((name, start, length))

def lookupSplitName(splitList, offset, end):
    for (name, start, end) in splitList:
        if offset == start and end == end:
            return name
    return None

def outputGroupAndRegion(outputFile, splitList, values):
    if values.has_key('lokey') and values.has_key('hikey') and values.has_key('pitch_keycenter'):
        outputFile.write('<group> lokey=%s hikey=%s pitch_keycenter=%s\n' % (values['lokey'], values['hikey'], values['pitch_keycenter']))
    elif values.has_key('key') and values.has_key('pitch_keycenter'):
        outputFile.write('<group> key=%s pitch_keycenter=%s\n' % (values['key'], values['pitch_keycenter']))
    if len(values) > 3:
        outputFile.write('    <region> ')
        if values.has_key('lovel') and values.has_key('hivel'):
            outputFile.write('lovel=%s hivel=%s ' % (values['lovel'], values['hivel']))
        if values.has_key('tune'):
            outputFile.write('tune=%s ' % values['tune'])
        if values.has_key('volume'):
            outputFile.write('volume=%s ' % values['volume'])
        if values.has_key('offset'):
            outputFile.write('offset=0 ')
        if values.has_key('end'):
            outputFile.write('end=%d ' % (int(values['end']) - int(values['offset'])))
        if values.has_key('loop_mode'):
            outputFile.write('loop_mode=%s ' % values['loop_mode'])
        if values.has_key('loop_start'):
            outputFile.write('loop_start=%d ' % (int(values['loop_start']) - int(values['offset'])))
        if values.has_key('loop_end'):
            outputFile.write('loop_end=%d ' % (int(values['loop_end']) - int(values['offset'])))
        outputFile.write('sample=samples/%s' % lookupSplitName(splitList, int(values['offset']), int(values['end'])) + '.wav\n')

def process(inputFile, outputFile):

    # create a list of region labels
    regionLabels = list()
    for line in open(inputFile):
        if line.strip().startswith('region_label'):
            regionLabels.append(line.strip().split('=')[1])

    # read entire input SFZ file
    sfz = open(inputFile).read()

    # strip comments and create a mixed list of <header> tags and key=value pairs
    sfz_list = stripComments(sfz).split()

    inSection = "none"
    default_path = ""
    global_sample = None
    values = dict()
    splitList = set()

    # parse the input SFZ data and build up splitList
    for item in sfz_list:
        if item.startswith('<'):
            inSection = item
            updateSplitList(splitList, regionLabels, values)
            values.clear()
            continue
        elif item.find('=') < 0:
            #print 'unknown:', item
            continue

        key, value = item.split('=')
        if inSection == '<control>' and key == 'default_path':
            default_path = value.replace('\\', '/')
        elif inSection == '<global>' and key == 'sample':
            global_sample = value.replace('\\', '/')
        elif inSection == '<region>':
            values[key] = value

    # split the wav file
    bigWav = AudioSegment.from_wav(global_sample)
    #print "%d channels, %d bytes/sample, %d frames/sec" % (bigWav.channels, bigWav.sample_width, bigWav.frame_rate)
    frate = float(bigWav.frame_rate)
    for (name, start, length) in splitList:
        startMs = 1000 * start / frate
        endMs = 1000 * (start + length) / frate
        wav = bigWav[startMs : endMs]
        wavName = 'samples/' + name + '.wav'
        wav.export(wavName, format='wav')

    # parse the input SFZ data again and generate the output SFZ
    for item in sfz_list:
        if item.startswith('<'):
            inSection = item
            outputGroupAndRegion(outputFile, splitList, values)
            values.clear()
            continue
        elif item.find('=') < 0:
            #print 'unknown:', item
            continue

        key, value = item.split('=')
        if inSection == '<control>' and key == 'default_path':
            default_path = value.replace('\\', '/')
        elif inSection == '<global>' and key == 'sample':
            global_sample = value.replace('\\', '/')
        elif inSection == '<region>':
            values[key] = value


dirPath = '000'
fileNameList = os.listdir(dirPath)
for fileName in fileNameList:
    if fileName.endswith('.sfz'):
        inputFile = os.path.join(dirPath, fileName)
        outputFile = open(fileName, 'w')
        print fileName
        process(inputFile, outputFile)
...