ios - 使用 AKSampleDescriptor
<p><p><strong>使用 AKSamplerDescriptor</strong></p>
<p>我正在使用一个改编的 AKSampler 示例,在该示例中我尝试使用 Fluid.sf3 melodicSounds 的 sforzando 输出。 Sforzando 为每个乐器创建 .sfz 文件,但所有文件都将全局样本指向一个巨大的 .wav 文件。</p>
<p>在所有的instrument.sfz 文件中,对于要使用的波形文件部分,都有一个偏移量和端点描述。 </p>
<p>当我加载 .sfz 文件时,由于内存问题,我遇到了崩溃。似乎对于 .sfz 文件中的每个已定义区域,都会再次加载完整的 .wav 文件 (140 mB)。 </p>
<p>最有可能的是,在重新加载完整的 .wav 文件时,如 AKSampler 示例中所做的那样使用 AKSampleDescriptor 加载示例文件将忽略偏移量和端点(AKSampleDescriptor.startPoint 和 AKSampleDescriptor.endPoint)。</p>
<p>有没有办法从样本文件中从头到尾加载所需的部分,因为完整的文件包含所有乐器的所有样本数据(我知道并使用当时只提取一种乐器的复音并且工作正常,但这是用于其他用途)</p>
<p>或者,这对我来说似乎是最好的,只需加载一次文件,然后让 sampledescriptors 指向内存中的数据</p></p>
<br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
<p><p>很好的建议,Rob。我自己也遇到了这个巨大的 WAV 问题,以前从未见过。我也在使用 Sforzando 进行转换。我将考虑向 AKSampler 添加必要的功能。同时,编写一个程序将一个 WAV 文件切割成更小的部分并相应地调整 SFZ 可能会更容易。</p>
<p>这里有一些 Python 2.7 代码来执行此操作,我已成功地将其与 Sforzando 转换的 sf2 soundfont 一起使用。它可能需要更改才能为您工作——sfz 文件之间存在巨大差异——但至少它可能会帮助您入门。此代码需要 <a href="http://pydub.com/" rel="noreferrer noopener nofollow">PyDub</a>用于处理 WAV 音频的库。</p>
<pre><code>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('='))
# 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 = 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
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 = 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)
</code></pre></p>
<p style="font-size: 20px;">关于ios - 使用 AKSampleDescriptor,我们在Stack Overflow上找到一个类似的问题:
<a href="https://stackoverflow.com/questions/53023548/" rel="noreferrer noopener nofollow" style="color: red;">
https://stackoverflow.com/questions/53023548/
</a>
</p>
页:
[1]