Synthesiser类群详解 3-1

使用JUCE开发MIDI软音源,软件合成器、采样器等是同一个概念,音频数据的来源不同而已 。主要涉及到以下几个类:

  • SynthesiserSound 及其派生类 SampleSound
  • SynthesiserVoice 及其派生类 SampleVoice
  • Synthesiser

SynthesiserSound

SynthesiserSound代表磁盘中的一个音频文件或内部产生的一个音频数据。即:用来“描述”一个合成音。该合成音由SynthesiserVoice“渲染”后,供Synthesiser合成器使用。一个合成器可持有(包容)一到多个合成音,每个合成音可指定所对应的MIDI音符和MIDI通道。即:一个合成音可被多个MIDI音符或多个MIDI通道所触发,一个MIDI音符或一个MIDI通道的MIDI事件也可触发多个不同的合成音,每个合成音即本类的一个对象。

注意:SynthesiserSound仅是描述声音“类型”的概念类,它所描述的声音由SynthesiserVoice来完成“渲染”,多个SynthesiserVoice对象可同时“渲染”本类的同一个对象。

SynthesiserSound是一个抽象基类,继承自ReferenceCountedObject类,又派生出SampleSound。

SynthesiserSound

图 3 17 SynthesiserSound类的继承层次

SynthesiserSound继承自ReferenceCountedObject类,类中对ReferenceCountedObjectPtr做了类型重定义,成为地地道道、方便易用的引用计数类。该类使用指针时,无需也不要使用传统的声明语句,而是这么写:

// SampleSound是SynthesiserSound的子类
SynthesiserSound::Ptr pointer = new SampleSound (..);

Synthesiser合成器类用于添加SynthesiserSound合成音的核心函数addSound(),其形参的数据类型就是SynthesiserSound::Ptr,即该形参为SynthesiserSound类的引用计数指针。

SynthesiserSound只有两个成员函数,且都是纯虚函数:
 appliesToNote (MIDI音符的编号) 如果给出的MIDI音符可触发本对象,则返回true
 appliesToChannel (MIDI通道的索引) 如果给定通道的MIDI事件可触发本对象,则返回true

Synthesiser将依据这两个函数决定某个MIDI通道的某个MIDI音符是否可触发本类所描述的声音。

SynthesiserSound因继承ReferenceCounterdbject引用计数类而拥有以下3个成员函数:
 incReferenceCount () 增加本对象的引用计数
 decReferenceCount () 减少本对象的引用计数
 getReferenceCount () 返回本对象的引用个数,即获取当前有几个指针指向本对象

仅凭一个抽象的SynthesiserSound不能看出更多端倪,那就研究一下它的派生类:SampleSound.

SampleSound因继承自SynthesiserSound,也成为引用计数类。该类的对象在创建时,将尝试把所持有的整个音频缓冲数据加载到内存中。其内部原理是:利用本类的构造参数AudioFormatReader对象,将该对象所代表的音频数据传送给本类的数据成员AudioSampleBuffer 。可简单的理解为:SampleSound对象在创建时,直接将磁盘文件中的音频数据保存到AudioSampleBuffer中,供系统中其它类所调用。即:本类代表了一个位于内存中、随时听候调用的音频文件。比如:某个乐器的采样录音(注意:此处使用的“采样”为电脑音乐方面的术语,不同于DSP和音频编程时的“采样”,编程时所说的采样指的是某个时间点对信号的取值,即一个float数值。要结合上下文进行区别,勿混淆)。

SampleSound的构造函数
SamplerSound (String& name, // 本采样的文本名称
AudioFormatReader& source, // 用于读取磁盘文件中的音频数据
BigInteger& midiNotes, // 本采样可播放的MIDI音符的集合
int midiNoteForNormalPitch,// 本采样的MIDI“根音”(正常音高所对应的MIDI音符)
double attackTimeSecs, // 本采样发声时的触发秒数(从0音量到正常音量的缓始时间)
double releaseTimeSecs,// 停止发声时的释放秒数(从正常音量到0音量的缓释时间)
double maxSampleLength) // 本采样读取所持有的音频数据的最长秒数(假设音频采样的原始时间为10秒,此处设置为5,则每次发声,最长只播放该采样的前5秒。如果此处给出的值大于音频采样的原始时间,则最长也只能播放音频采样的原始时间。)

SampleSound新增的成员函数
 getName () 返回采样的名称
 getAudioData () 返回本对象所持有的音频数据(返回值为AudioSampleBuffer指针)

SampleSound对象在创建后,响应所有MIDI通道上的音符,所响应的音符范围由构造3参确定。从这一点即可看出,该类是专用于构建MIDI采样器的。即:忽略MIDI通道的限制,任何一个通道均可以加载并播放本类的音频采样。