使用mapply调用fillampenv函数时出现length.out非负数值错误排查
问题分析与解决方案
首先,咱们来揪出这个错误的根源:你碰到的'length.out' must be a non-negative number报错,核心原因是函数里那段用来保持音量为1的序列,计算出来的长度是负数!
拿你数据框里的参数实际算一遍就一目了然了:
- 音频总时长:
samples/samprate = 17640/44100 = 0.4秒 - 上升+下降的总时长:
rise + fall = 0.75 + 0.3 = 1.05秒
你看,上升加下降的时间(1.05秒)已经远远超过了整个音频的总时长(0.4秒),这就导致你计算中间保持段长度的公式:
(((samples/samprate) - (rise + fall)) * samprate) -1
算出来是((0.4 - 1.05)*44100) -1 = -28666——一个负数,而seq()函数的length.out参数要求必须是非负数,自然就触发错误了。
至于为什么其他函数用mapply没问题,那是因为那些函数的参数组合不会出现这种“计算出负数长度”的情况,而这个函数的逻辑刚好在你的参数下踩了这个坑。
修复方案
我们需要给函数加一层判断逻辑,先检查总时长是否足够覆盖上升+下降的时间,如果不够就跳过中间保持的部分,同时还要处理样本数必须是整数的问题:
fillampenv <- function(samples, samprate, rise, fall){ total_dur <- samples / samprate # 把时长转成整数样本数,避免小数导致的长度偏差 rise_samples <- round(rise * samprate) fall_samples <- round(fall * samprate) # 计算中间保持的样本数,强制保证非负 hold_samples <- samples - rise_samples - fall_samples hold_samples <- max(hold_samples, 0) # 分三段构建包络,中间段长度为0时直接返回空向量 v <- c( seq(0, 1, length.out = rise_samples), if(hold_samples > 0) rep(1, hold_samples) else numeric(0), seq(1, 0, length.out = fall_samples) ) # 最后兜底:确保最终向量长度和输入的samples完全一致 if(length(v) != samples){ v <- if(length(v) > samples) v[1:samples] else c(v, rep(0, samples - length(v))) } return(v) }
这个修复做了这几件关键的事:
- 用
round()把时长转成整数样本数,避免小数样本数的不合理情况 - 用
max(hold_samples, 0)强制保证中间段长度不会出现负数 - 当中间段长度为0时,直接返回空向量,跳过无效的
seq()调用 - 最后检查并调整最终向量长度,确保和输入的
samples完全匹配
现在再用你的mapply代码调用:
ampenvs <- mapply(fillampenv, samples = df$samples, samprate = df$samprate, rise = df$rise, fall = df$fall)
就不会再报错了。
内容的提问来源于stack exchange,提问作者pajul
相关产品推荐
相关产品推荐

