0

根据参考 csound 手册,在编写响应 MIDI 的乐器时应该使用xtratim(或隐式使用它的操作码,例如),因为事先不知道键/音符的持续时间(对于现场表演)。madsr

但是,我还在一个外部示例中注意到,可以从乐器代码中覆盖 p3(乐谱音符长度)。那么,这样做和使用之间有什么区别xtratim吗?

4

2 回答 2

1

是的,当音符关闭时,具有发布段的 xtratim 和 -r 操作码将触发额外的发布时间。p3 将只是“开启”时间的持续时间值。

例如,如果您运行以下命令:

instr S1
  p3 = 2
  asig = oscili(0.25, 440)
  asig *= linsegr(1, .1, 1, 4, 0)
  out(asig, asig)
endin
schedule("S1", 0, 0.1)
  1. 调度调用将 p3 设置为 0.1 秒
  2. 仪器将 p3 重新定义为 2 秒
  3. 由于 linsegr 释放值,仪器运行 2 秒,之后有 4 秒释放时间

通常,应谨慎使用覆盖 p3,但它适用于某些情况,例如确保为仪器提供最少的时间。xtratim 或 -r 操作码的发布时间可能更适用于大多数用例。

于 2020-02-16T19:16:13.170 回答
0

由于xtratim获得了 i-arg 额外的时间,我希望改变 p3 会更灵活,但实际上并非如此......

对于初学者,p3 被视为 i-var,即它只能在初始传递时分配,所以类似于

instr 1
if p3 < 9 then
  p3 = p3 + 1 ; runs only once
  printk 0.1, p3
endif
endin

如果从得分中调用,则只会运行三秒钟

i1 0 2

这是意料之中的事。另一方面,调用reinit[re]run 初始化阶段的以下 hack 确实不止一次更新 p3,但这对音符播放时间的影响为零,即只有第一个(“真正的 init”)改变了实际的音符持续时间... perf-time 重新初始化,同时更改从乐器读取的 p3,对音符播放持续时间没有任何影响,即

top:
p3  = p3 + 1
printk 0.1, p3
if p3 < 9 then
  reinit top
endif

仍然以相同的分数播放 3 秒(即使我确保 Csound 运行时间足够长),即:

i1 0 2
e 10

尽管 printk 确实将 p3 显示为使用后一种仪器达到值 9...

至于xtratim它根本不会改变 p3,正如 Steven' Yi 的回答正确指出的那样,“额外时间”是在此之外实施的。

查看 xtratim 的源代码,实际上可以通过多次调用 xtratim 来延长“额外时间”,并不断增加值,但不能缩短它......

int32_t xtratim(CSOUND *csound, XTRADUR *p)
{
    IGN(csound);
    int32_t *xtra = &(p->h.insdshead->xtratim);
    int32_t tim = (int32_t)(*p->extradur * p->h.insdshead->ekr);
    if (*xtra < tim)  /* gab-a5 revised */
      *xtra = tim;
    return OK;
}

有了这些信息,我尝试了

ixtr = 0
top:
ixtr += 1
xtratim ixtr
print ixtr
if ixtr < 8 then
  reinit top
endif

你瞧,后面的 hack 确实有效,即后面的代码实际上使用之前的分数将乐器/音符的播放时间延长到 10 秒。因此,与破解 p3 不同,可以在演奏时从仪器内部以这种方式以编程方式扩展音符,随心所欲地扩展音符。

对于那些好奇的人,xtratim即使在发布已被断言之后调用,甚至在播放(实际发布)时间(正确地)生效,即即使从“发布段”,例如

xtratim 1
kflag release
kdone init 0
if (kflag == 1) && (kdone == 0)  then
  kdone = 1
  reinit more
  more:
  xtratim 4
endif

将额外提供 4 秒的播放时间。鉴于此,我不确定在 perf 期间忽略 p3 更新是错误还是“设计使然”。

于 2020-02-16T07:01:14.210 回答