Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1146 lines
47 KiB

  1. // Synth.h
  2. // Copyright (c) 1996-2000 Microsoft Corporation. All Rights Reserved.
  3. //
  4. /*
  5. DLS Design Overview (DLS Level 1 Specification, MMA)
  6. A musical instruments defined by a sound sample is much more than a simple wave file.
  7. In addition to the actual sample data and associated loop information, the instrument
  8. must indicate under what circumstances each sample should be used, and how to modulate,
  9. or articulate, the sample as it plays.
  10. A generic sample-playback synthesis architecture can be broken down into three distinct
  11. subsystems:
  12. Control logic
  13. Digital audio engine
  14. Articulation modules and connections
  15. Control Logic
  16. The control logic receives a MIDI note event and determines which instrument should play
  17. the note, and, within that instrument, which sample and articulation combination to use.
  18. Choosing the instrument is little more than observing the MIDI channel number in the
  19. event and selecting the proper instrument accordingly.
  20. Choosing the sample and articulation to use is not as simple. Almost all samples synthesis
  21. architectures employ some method of organizing samples by note range across the keyboard.
  22. In addition, multiple samples can be used to represent different velocity randges and
  23. multiple samples can be played at once to create a layered, richer sound.
  24. Terms such as layers, splits, blocks, and regions are commonly used in synthesizer jargon
  25. to refer to the management of multiple samples. For the purposes here, we refer to them
  26. as regions.
  27. DLS Level 1 implements a bare bones approach with no velocity cross-switching and no
  28. layering.
  29. Digital Audio Engine
  30. The digital audio engine is certainly the most obvious part of the synthesizer. It is
  31. composed of a playback engine, or digital oscillator, and a digitally controlled amplifier.
  32. The digital oscillator plays a samples sound waveform, managing loop points within the
  33. waveform so the sound can play continuously if needed. And, as the note plays, it responds
  34. to changes in pitch, allowing for real time expression such as vibrato and pitch bend.
  35. The digitally controlled amplirier modulates the loudness of the instrument. Importantly,
  36. this is used to control the amplitude shape, or envelope, of the note. However, it is also
  37. used for other types of real-time expression, such as tremolo.
  38. Pitch and volume control of the oscillator and amplifier are critical because they define
  39. the shape of the sounds as it plays, and allow it to be dynamically responsive in real
  40. time, giving the samples instrument much more expression than the simple digital audio
  41. playback could ever provide. Real-time control of these parameters comes from modules in
  42. the Articulation section which generate a constant stream of changing pitch and volume to
  43. which the digital audio engine responds.
  44. The digital audio path represents the journey the sound takes from the oscillator to the
  45. amplifier to the digital-to-analog converter (DAC). This patch can optionally include
  46. additional modules, such as filters and effects devices, that process the sound as it
  47. flows from oscillator to DAC.
  48. The DLS Level 1 specificaion implements a simple digital audio engine composed of an
  49. oscillator, amplifier, and DAC. The oscillator supports looped as well as one-shot samples.
  50. Articulation Modules and Connections
  51. The articulation modules are a set of devices that provide additional control over the
  52. pitch and volume of the sample as it plays.
  53. The articulation modules include low frequency oscillators (LFOs) to contribute vibrato
  54. and tremolo, envelope generators to defint an overall volume and pitch shape to the sample,
  55. and MIDI real-time controllers, such as Pitch Bend and Mod Wheel, to give the music real-time
  56. expression.
  57. Generally, these modules can be linked in different ways to provide different results. For
  58. example, a LFO might generate a sine wave which modulates the pitch of the sample for vibrato
  59. of the volume of the sample for tremolo. Modules can also receive as well as send control
  60. signals. An envelope generator might use the key velocity to influence the attack time of
  61. the envelope.
  62. Articulation modules can be configured in different ways, and this configuration is an
  63. important part of the instrument definition. In fact, the term patch as used for an
  64. instrument preset refers to the early days when the hardware modules in an analog
  65. synthesizer were "patched" together with cables, which routed signals from module to module.
  66. The ability to configure the modules in important because it yields a flexible approach to
  67. synthesizer design. At the same time, it is important to define the base level configuration
  68. that can be supported by all hardware.
  69. So, the DLS Level 1 specification is relatively rigid. It defines a preset routing
  70. arrangement that is simple enough to be supportable by existing hardware. Fortunately, it
  71. is a musically logical and useful configuration.
  72. Importantly, the specification maps the routing on a flexible system, so it can grow into
  73. Level 2 and beyond.
  74. It is important to understand that this is purely a symbolic system that can be mapped on
  75. many different hardware designs. Do not think of it as the recipe for a specific method
  76. for building synthesis architectures. It should be flexible enough to provide a common
  77. language between hardware implementations.
  78. */
  79. #ifndef __SYNTH_H__
  80. #define __SYNTH_H__
  81. #include "clist.h"
  82. #include "dmdls.h"
  83. #define MIDI_NOTEOFF 0x80
  84. #define MIDI_NOTEON 0x90
  85. #define MIDI_PTOUCH 0xA0
  86. #define MIDI_CCHANGE 0xB0
  87. #define MIDI_PCHANGE 0xC0
  88. #define MIDI_MTOUCH 0xD0
  89. #define MIDI_PBEND 0xE0
  90. #define MIDI_SYSX 0xF0
  91. #define MIDI_MTC 0xF1
  92. #define MIDI_SONGPP 0xF2
  93. #define MIDI_SONGS 0xF3
  94. #define MIDI_EOX 0xF7
  95. #define MIDI_CLOCK 0xF8
  96. #define MIDI_START 0xFA
  97. #define MIDI_CONTINUE 0xFB
  98. #define MIDI_STOP 0xFC
  99. #define MIDI_SENSE 0xFE
  100. // controller numbers
  101. #define CC_BANKSELECTH 0x00
  102. #define CC_BANKSELECTL 0x20
  103. #define CC_MODWHEEL 0x01
  104. #define CC_VOLUME 0x07
  105. #define CC_PAN 0x0A
  106. #define CC_EXPRESSION 0x0B
  107. #define CC_SUSTAIN 0x40
  108. #define CC_ALLSOUNDSOFF 0x78
  109. #define CC_RESETALL 0x79
  110. #define CC_ALLNOTESOFF 0x7B
  111. #define CC_MONOMODE 0x7E
  112. #define CC_POLYMODE 0x7F
  113. // rpn controllers
  114. #define CC_DATAENTRYMSB 0x06
  115. #define CC_DATAENTRYLSB 0x26
  116. #define CC_NRPN_LSB 0x62
  117. #define CC_NRPN_MSB 0x63
  118. #define CC_RPN_LSB 0x64
  119. #define CC_RPN_MSB 0x65
  120. // registered parameter numbers
  121. #define RPN_PITCHBEND 0x00
  122. #define RPN_FINETUNE 0x01
  123. #define RPN_COARSETUNE 0x02
  124. /* Sample format and Sample playback flags are organized
  125. together because together they determine which
  126. mix loop to use.
  127. */
  128. #define SFORMAT_16 1 // Sixteen bit sample.
  129. #define SFORMAT_8 2 // Eight bit sample.
  130. #define SPLAY_MMX 0x10 // Use MMX processor (16 bit only).
  131. #define SPLAY_STEREO 0x40 // Stereo output.
  132. /* For internal representation, volume is stored in Volume Cents,
  133. where each increment represents 1/100 of a dB.
  134. Pitch is stored in Pitch Cents, where each increment
  135. represents 1/100 of a semitone.
  136. */
  137. typedef long PREL; // Pitch cents, for relative pitch.
  138. typedef short PRELS; // Pitch cents, in storage form.
  139. typedef long VREL; // Volume cents, for relative volume.
  140. typedef short VRELS; // Volume cents, in storage form.
  141. typedef long TREL; // Time cents, for relative time
  142. typedef short TRELS; // Time Cents, in storage form.
  143. typedef LONGLONG STIME; // Time value, in samples.
  144. typedef long MTIME; // Time value, in milliseconds.
  145. typedef long PFRACT; // Pitch increment, where upper 20 bits are
  146. // the index and the lower 12 are the fractional
  147. // component.
  148. typedef long VFRACT; // Volume, where lower 12 bits are the fraction.
  149. typedef long TCENT;
  150. typedef short SPERCENT;
  151. #define MIN_VOLUME -9600 // Below 96 db down is considered off.
  152. #define PERCEIVED_MIN_VOLUME -8000 // But, we cheat.
  153. #define SAMPLE_RATE_22 22050 // 22 kHz is the standard rate.
  154. #define SAMPLE_RATE_44 44100 // 44 kHz is the high quality rate.
  155. #define SAMPLE_RATE_11 11025 // 11 kHz should not be allowed!
  156. #define STEREO_ON 1
  157. #define STEREO_OFF 0
  158. #define FORCEBOUNDS(data,min,max) {if (data < min) data = min; else if (data > max) data = max;}
  159. #define FORCEUPPERBOUNDS(data, max) {if (data > max) data = max;}
  160. class Collection;
  161. class CControlLogic;
  162. class CInstManager;
  163. class CSynth;
  164. /*****************************************************************************
  165. * class CSourceLFO
  166. *****************************************************************************
  167. * CSourceLFO is the file format definition of the LFO in an
  168. * instrument. This is used to represent an LFO as part of
  169. * a specific articulation set within an instrument that
  170. * has been loaded from disk. Once the instrument is chosen
  171. * to play a note, this is also copied into the CVoice
  172. * object.
  173. */
  174. class CSourceLFO
  175. {
  176. public:
  177. CSourceLFO();
  178. void Init(DWORD dwSampleRate);
  179. void SetSampleRate(long lDirection);
  180. void Verify(); // Verifies that the data is valid.
  181. PFRACT m_pfFrequency; // Frequency, in increments through the sine table.
  182. STIME m_stDelay; // How long to delay in sample units.
  183. VRELS m_vrMWVolumeScale; // Scaling of volume LFO by Mod Wheel.
  184. PRELS m_prMWPitchScale; // Scaling of pitch LFO by Mod Wheel.
  185. VRELS m_vrVolumeScale; // Scaling of straight volume signal from LFO.
  186. PRELS m_prPitchScale; // Scaling of straight pitch signal from LFO.
  187. };
  188. /*****************************************************************************
  189. * class CSourceEG
  190. *****************************************************************************
  191. * CSourceEG is the file format definition of an Envelope
  192. * generator in an instrument.
  193. */
  194. class CSourceEG
  195. {
  196. public:
  197. CSourceEG();
  198. void SetSampleRate(long lDirection);
  199. void Init();
  200. void Verify(); // Verifies valid data.
  201. STIME m_stAttack; // Attack rate.
  202. STIME m_stDecay; // Decay rate.
  203. STIME m_stRelease; // Release rate.
  204. TRELS m_trVelAttackScale; // Scaling of attack by note velocity.
  205. TRELS m_trKeyDecayScale; // Scaling of decay by note value.
  206. SPERCENT m_pcSustain; // Sustain level.
  207. short m_sScale; // Scaling of entire signal.
  208. };
  209. /*****************************************************************************
  210. * class CSourceArticulation
  211. *****************************************************************************
  212. * CSourceArticulation is the file format definition of
  213. * a complete articulation set: the LFO and two
  214. * envelope generators.
  215. *
  216. * Since several regions within one Instrument can
  217. * share one articulation, a counter is used to keep
  218. * track of the usage.
  219. */
  220. class CSourceArticulation
  221. {
  222. public:
  223. CSourceArticulation();
  224. HRESULT Download( DMUS_DOWNLOADINFO * pInfo,
  225. void * pvOffsetTable[], DWORD dwIndex,
  226. DWORD dwSampleRate, BOOL fNewFormat);
  227. void Init(DWORD dwSampleRate);
  228. void Verify(); // Verifies valid data.
  229. void AddRef();
  230. void Release();
  231. void SetSampleRate(DWORD dwSampleRate);
  232. CSourceEG m_PitchEG; // Pitch envelope.
  233. CSourceEG m_VolumeEG; // Volume envelope.
  234. CSourceLFO m_LFO; // Low frequency oscillator.
  235. DWORD m_dwSampleRate;
  236. WORD m_wUsageCount; // Keeps track of how many times in use.
  237. short m_sDefaultPan; // default pan (for drums)
  238. };
  239. /*****************************************************************************
  240. * class CWave
  241. *****************************************************************************
  242. * Since multiple regions may reference
  243. * the same Wave, a reference count is maintained to
  244. * keep track of how many regions are using the sample.
  245. */
  246. class CWave : public CListItem
  247. {
  248. public:
  249. CWave();
  250. ~CWave();
  251. void Verify(); // Verifies that the data is valid.
  252. void Release(); // Remove reference.
  253. void AddRef(); // Add reference.
  254. void PlayOn(); // Increment play count.
  255. void PlayOff(); // Decrement play count.
  256. BOOL IsPlaying(); // Is currently playing?
  257. CWave * GetNext() {return(CWave *)CListItem::GetNext();};
  258. DWORD m_dwSampleLength; // Length of sample.
  259. DWORD m_dwSampleRate;
  260. HRESULT ( CALLBACK *m_lpFreeHandle)(HANDLE,HANDLE);
  261. HANDLE m_hUserData; // Used to notify app when wave released.
  262. short * m_pnWave;
  263. DWORD m_dwID; // ID for matching wave with regions.
  264. WORD m_wUsageCount; // Keeps track of how many times in use.
  265. WORD m_wPlayCount; // Wave is currently being played.
  266. BYTE m_bSampleType;
  267. DMUS_DOWNLOADINFO * m_pWaveMem;
  268. };
  269. /*****************************************************************************
  270. * class CWavePool
  271. *****************************************************************************
  272. * implements a list of wave objects.
  273. */
  274. class CWavePool : public CList
  275. {
  276. public:
  277. CWave * GetHead() {return (CWave *)CList::GetHead();};
  278. CWave * GetItem(DWORD dwID) {return (CWave *)CList::GetItem((LONG)dwID);};
  279. CWave * RemoveHead() {return (CWave *)CList::RemoveHead();};
  280. };
  281. /*****************************************************************************
  282. * class CSourceSample
  283. *****************************************************************************
  284. * The CSourceSample class describes one sample in an
  285. * instrument. The sample is referenced by a CSourceRegion
  286. * structure.
  287. */
  288. class CSourceSample
  289. {
  290. public:
  291. CSourceSample();
  292. ~CSourceSample();
  293. BOOL CopyFromWave();
  294. void Verify(); // Verifies that the data is valid.
  295. CWave * m_pWave; // Wave in pool.
  296. DWORD m_dwLoopStart; // Index of start of loop.
  297. DWORD m_dwLoopEnd; // Index of end of loop.
  298. DWORD m_dwSampleLength; // Length of sample.
  299. DWORD m_dwSampleRate; // Sample rate of recording.
  300. PRELS m_prFineTune; // Fine tune to correct pitch.
  301. DWORD m_dwID; // Wave pool id.
  302. BYTE m_bSampleType; // 16 or 8.
  303. BYTE m_bOneShot; // Is this a one shot sample?
  304. BYTE m_bMIDIRootKey; // MIDI note number for sample.
  305. };
  306. /*****************************************************************************
  307. * class CSourceRegion
  308. *****************************************************************************
  309. * The CSourceRegion class defines a region within an instrument.
  310. * The sample is managed with a pointer instead of an embedded
  311. * sample. This allows multiple regions to use the same sample.
  312. *
  313. * Each region also has an associated articulation. For drums, there
  314. * is a one to one matching. For melodic instruments, all regions
  315. * share the same articulation. So, to manage this, each region
  316. * points to the articulation.
  317. */
  318. class CSourceRegion : public CListItem
  319. {
  320. public:
  321. CSourceRegion();
  322. ~CSourceRegion();
  323. CSourceRegion *GetNext()
  324. {return(CSourceRegion *)CListItem::GetNext();};
  325. void Verify(); // Verifies that the data is valid.
  326. void SetSampleRate(DWORD dwSampleRate);
  327. HRESULT Download( DMUS_DOWNLOADINFO * pInfo, void * pvOffsetTable[],
  328. DWORD *pdwRegionIX, DWORD dwSampleRate, BOOL fNewFormat);
  329. CSourceSample m_Sample; // Sample structure.
  330. CSourceArticulation * m_pArticulation; // Pointer to associated articulation.
  331. VRELS m_vrAttenuation; // Volume change to apply to sample.
  332. PRELS m_prTuning; // Pitch shift to apply to sample.
  333. BYTE m_bAllowOverlap; // Allow overlapping of note.
  334. BYTE m_bKeyHigh; // Upper note value for region.
  335. BYTE m_bKeyLow; // Lower note value.
  336. BYTE m_bGroup; // Logical group (for drums.)
  337. };
  338. /*****************************************************************************
  339. * class CSourceRegionList
  340. *****************************************************************************
  341. * implements a list of CSourceRegion objects.
  342. */
  343. class CSourceRegionList : public CList
  344. {
  345. public:
  346. CSourceRegion *GetHead() {return (CSourceRegion *)CList::GetHead();};
  347. CSourceRegion *RemoveHead() {return (CSourceRegion *)CList::RemoveHead();};
  348. };
  349. /*****************************************************************************
  350. * class CInstrument
  351. *****************************************************************************
  352. * The CInstrument class is really the file format definition
  353. * of an instrument.
  354. *
  355. * The CInstrument can be either a Drum or a Melodic instrument.
  356. * If a drum, it has up to 128 pairings of articulations and
  357. * regions. If melodic, all regions share the same articulation.
  358. * ScanForRegion is called by ControlLogic to get the region
  359. * that corresponds to a note.
  360. */
  361. class CInstrument : public CListItem
  362. {
  363. public:
  364. CInstrument();
  365. ~CInstrument();
  366. void Init(DWORD dwSampleRate);
  367. void Verify(); // Verifies that the data is valid.
  368. CInstrument * GetInstrument(DWORD dwProgram,DWORD dwAccept);
  369. CInstrument * GetNext()
  370. {return(CInstrument *)CListItem::GetNext();};
  371. void SetSampleRate(DWORD dwSampleRate);
  372. CSourceRegion * ScanForRegion(DWORD dwNoteValue);
  373. HRESULT LoadRegions( BYTE *p, BYTE *pEnd, DWORD dwSampleRate);
  374. HRESULT Load( BYTE *p, BYTE *pEnd, DWORD dwSampleRate);
  375. CSourceRegionList m_RegionList; // Linked list of regions.
  376. DWORD m_dwProgram; // Which program change it represents.
  377. };
  378. /*****************************************************************************
  379. * class CInstrumentList
  380. *****************************************************************************
  381. * Implements a list of CInstrument objects.
  382. */
  383. class CInstrumentList : public CList
  384. {
  385. public:
  386. CInstrument * GetHead() {return (CInstrument *)CList::GetHead();};
  387. CInstrument * RemoveHead() {return (CInstrument *)CList::RemoveHead();};
  388. };
  389. #define WAVE_HASH_SIZE 31 // Keep waves in a hash table of linked lists to speed access.
  390. #define INSTRUMENT_HASH_SIZE 31 // Same with instruments.
  391. /*****************************************************************************
  392. * class CInstManager
  393. *****************************************************************************
  394. * Manages the instruments, including sample rates, downloads, and waves.
  395. * Utilizes a hash scheme for quick location of waves and instruments
  396. * (they can become numerous).
  397. */
  398. class CInstManager
  399. {
  400. public:
  401. CInstManager();
  402. ~CInstManager();
  403. CInstrument * GetInstrument(DWORD dwPatch,DWORD dwKey);
  404. void Verify(); // Verifies that the data is valid.
  405. void SetSampleRate(DWORD dwSampleRate);
  406. HRESULT Download(LPHANDLE phDownload,
  407. void * pvData,
  408. LPBOOL pbFree);
  409. HRESULT Unload(HANDLE hDownload,
  410. HRESULT ( CALLBACK *lpFreeHandle)(HANDLE,HANDLE),
  411. HANDLE hUserData);
  412. private:
  413. HRESULT DownloadInstrument(LPHANDLE phDownload,
  414. DMUS_DOWNLOADINFO *pInfo,
  415. void *pvOffsetTable[],
  416. void *pvData,
  417. BOOL fNewFormat);
  418. HRESULT DownloadWave(LPHANDLE phDownload,
  419. DMUS_DOWNLOADINFO *pInfo,
  420. void *pvOffsetTable[],
  421. void *pvData);
  422. CInstrumentList m_InstrumentList[INSTRUMENT_HASH_SIZE];
  423. CWavePool m_WavePool[WAVE_HASH_SIZE];
  424. CWavePool m_FreeWavePool; // Track waves still in use, but unloaded.
  425. DWORD m_dwSampleRate; // Sample rate requested by app.
  426. public:
  427. CRITICAL_SECTION m_CriticalSection; // Critical section to manage access.
  428. BOOL m_fCSInitialized;
  429. };
  430. /*****************************************************************************
  431. * class CMIDIData
  432. *****************************************************************************
  433. * Represents a single MIDI event.
  434. */
  435. class CMIDIData : public CListItem
  436. {
  437. public:
  438. CMIDIData();
  439. CMIDIData * GetNext() {return (CMIDIData *)CListItem::GetNext();};
  440. STIME m_stTime; // Time this event was recorded.
  441. long m_lData; // Data stored in event.
  442. };
  443. /*****************************************************************************
  444. * class CMIDIDataList
  445. *****************************************************************************
  446. * Implements a list of CMIDIData objects.
  447. */
  448. class CMIDIDataList : public CList
  449. {
  450. public:
  451. CMIDIData *GetHead() {return (CMIDIData *)CList::GetHead();};
  452. CMIDIData *RemoveHead() {return (CMIDIData *)CList::RemoveHead();};
  453. };
  454. #define MAX_MIDI_EVENTS 1000
  455. /*****************************************************************************
  456. * class CMIDIRecorder
  457. *****************************************************************************
  458. * CMIDIRecorder is used to keep track of a time
  459. * slice of MIDI continuous controller events.
  460. * This is subclassed by the PitchBend, Volume,
  461. * Expression, and ModWheel Recorder classes, so
  462. * each of them may reliably manage MIDI events
  463. * coming in.
  464. *
  465. * CMIDIRecorder uses a linked list of CMIDIData
  466. * structures to keep track of the changes within
  467. * the time slice.
  468. *
  469. * Allocation and freeing of the CMIDIData events
  470. * is kept fast and efficient because they are
  471. * always pulled from the static pool m_pFreeList,
  472. * which is really a list of events pulled directly
  473. * from the static array m_sEventBuffer. This is
  474. * safe because we can make the assumption that
  475. * the maximum MIDI rate is 1000 events per second.
  476. * Since we are managing time slices of roughly
  477. * 1/16 of a second, a buffer of 100 events would
  478. * be overkill.
  479. *
  480. * Although CMIDIRecorder is subclassed to several
  481. * different event types, they all share the one
  482. * static free list.
  483. */
  484. class CMIDIRecorder
  485. {
  486. public:
  487. CMIDIRecorder();
  488. ~CMIDIRecorder(); // Be sure to clear local list.
  489. void Init(); // Inits the free list.
  490. static void InitTables();
  491. BOOL FlushMIDI(STIME stTime); // Clear after time stamp.
  492. BOOL ClearMIDI(STIME stTime); // Clear up to time stamp.
  493. BOOL RecordMIDI(STIME stTime, long lData); // MIDI input goes here.
  494. long GetData(STIME stTime); // Gets data at time.
  495. static VREL VelocityToVolume(WORD nVelocity);
  496. static CMIDIDataList * m_sFreeList; // Free list of events.
  497. static ULONG sm_cRefCnt; // ref count
  498. protected:
  499. void GrabSpinLock();
  500. void ReleaseSpinLock();
  501. CMIDIDataList m_EventList; // This recorder's list.
  502. STIME m_stCurrentTime; // Time for current value.
  503. long m_lCurrentData; // Current value.
  504. private:
  505. KSPIN_LOCK m_SpinLock;
  506. KIRQL m_OldIrql;
  507. };
  508. /*****************************************************************************
  509. * class CNote
  510. *****************************************************************************
  511. * Represents a single note. This can also represent fakes notes that
  512. * represent special MIDI commands (Master Volume, etc).
  513. */
  514. class CNote
  515. {
  516. public:
  517. STIME m_stTime;
  518. BYTE m_bPart;
  519. BYTE m_bKey;
  520. BYTE m_bVelocity;
  521. };
  522. /*****************************************************************************
  523. * Fake note values held in CNoteIn's queue to indicate changes in the
  524. * sustain pedal and "all notes off".
  525. *
  526. * This is a grab bag for synchronous events that should be queued in time,
  527. * not simply done as soon as received.
  528. *
  529. * By putting them in the note queue, we ensure they are evaluated in the
  530. * exact same order as the notes themselves.
  531. *****************************************************************************/
  532. const BYTE NOTE_PROGRAMCHANGE = 0xF1;
  533. const BYTE NOTE_CC_BANKSELECTH = 0xF2;
  534. const BYTE NOTE_CC_BANKSELECTL = 0xF3;
  535. const BYTE NOTE_CC_POLYMODE = 0xF4;
  536. const BYTE NOTE_CC_MONOMODE = 0xF5;
  537. const BYTE NOTE_CC_RPN_MSB = 0xF6;
  538. const BYTE NOTE_CC_RPN_LSB = 0xF7;
  539. const BYTE NOTE_CC_NRPN = 0xF8;
  540. const BYTE NOTE_CC_DATAENTRYLSB = 0xF9;
  541. const BYTE NOTE_CC_DATAENTRYMSB = 0xFA;
  542. const BYTE NOTE_ASSIGNRECEIVE = 0xFB;
  543. const BYTE NOTE_MASTERVOLUME = 0xFC;
  544. const BYTE NOTE_SOUNDSOFF = 0xFD;
  545. const BYTE NOTE_SUSTAIN = 0xFE;
  546. const BYTE NOTE_ALLOFF = 0xFF;
  547. /*****************************************************************************
  548. * class CNoteIn
  549. *****************************************************************************
  550. * Implements a note receptor. This is used by CControlLogic to queue notes.
  551. */
  552. class CNoteIn : public CMIDIRecorder
  553. {
  554. public:
  555. void FlushMIDI(STIME stTime);
  556. void FlushPart(STIME stTime, BYTE bChannel);
  557. BOOL RecordNote(STIME stTime, CNote * pNote);
  558. BOOL RecordEvent(STIME stTime, DWORD dwPart, DWORD dwCommand, BYTE bData);
  559. BOOL GetNote(STIME stTime, CNote * pNote); // Gets the next note.
  560. };
  561. /*****************************************************************************
  562. * class CModWheelIn
  563. *****************************************************************************
  564. * CModWheelIn handles one channel of Mod Wheel
  565. * input. As such, it is not embedded in the CVoice
  566. * class, rather it is in the Channel class.
  567. * CModWheelIn's task is simple: keep track of MIDI
  568. * Mod Wheel events, each tagged with millisecond
  569. * time and value, and return the value for a specific
  570. * time request.
  571. *
  572. * CModWheelIn inherits almost all of its functionality
  573. * from the CMIDIRecorder Class.
  574. * CModWheelIn receives MIDI mod wheel events through
  575. * the RecordMIDI() command, which stores the
  576. * time and value of the event.
  577. *
  578. * CModWheelIn is called by CVoiceLFO to get the
  579. * current values for the mod wheel to set the amount
  580. * of LFO modulation for pitch and volume.
  581. */
  582. class CModWheelIn : public CMIDIRecorder
  583. {
  584. public:
  585. DWORD GetModulation(STIME stTime); // Gets the current Mod Wheel value.
  586. };
  587. /*****************************************************************************
  588. * class CPitchBendIn
  589. *****************************************************************************
  590. * CPitchBendIn handles one channel of Pitch Bend
  591. * input. Like the Mod Wheel module, it inherits
  592. * its abilities from the CMIDIRecorder class.
  593. *
  594. * It has one additional routine, GetPitch(),
  595. * which returns the current pitch bend value.
  596. */
  597. class CPitchBendIn : public CMIDIRecorder
  598. {
  599. public:
  600. CPitchBendIn();
  601. PREL GetPitch(STIME stTime); // Gets the current pitch in pitch cents.
  602. // current pitch bend range. Note that this is not timestamped!
  603. PREL m_prRange;
  604. };
  605. /*****************************************************************************
  606. * class CVolumeIn
  607. *****************************************************************************
  608. * CVolumeIn handles one channel of Volume
  609. * input. It inherits its abilities from
  610. * the CMIDIRecorder class.
  611. *
  612. * It has one additional routine, GetVolume(),
  613. * which returns the volume in decibels at the
  614. * specified time.
  615. */
  616. class CVolumeIn : public CMIDIRecorder
  617. {
  618. public:
  619. CVolumeIn();
  620. VREL GetVolume(STIME stTime); // Gets the current volume in db cents.
  621. };
  622. /*****************************************************************************
  623. * class CExpressionIn
  624. *****************************************************************************
  625. * CExpressionIn handles one channel of Expression
  626. * input. It inherits its abilities from
  627. * the CMIDIRecorder class.
  628. *
  629. * It has one additional routine, GetVolume(),
  630. * which returns the volume in decibels at the
  631. * specified time.
  632. */
  633. class CExpressionIn : public CMIDIRecorder
  634. {
  635. public:
  636. CExpressionIn();
  637. VREL GetVolume(STIME stTime); // Gets the current volume in db cents.
  638. };
  639. /*****************************************************************************
  640. * class CPanIn
  641. *****************************************************************************
  642. * CPanIn handles one channel of Volume
  643. * input. It inherits its abilities from
  644. * the CMIDIRecorder class.
  645. *
  646. * It has one additional routine, GetPan(),
  647. * which returns the pan position (MIDI value)
  648. * at the specified time.
  649. */
  650. class CPanIn : public CMIDIRecorder
  651. {
  652. public:
  653. CPanIn();
  654. long GetPan(STIME stTime); // Gets the current pan.
  655. };
  656. /*****************************************************************************
  657. * class CVoiceLFO
  658. *****************************************************************************
  659. * The CVoiceLFO class is used to track the behavior
  660. * of an LFO within a voice. The LFO is hard wired to
  661. * output both volume and pitch values, through separate
  662. * calls to GetVolume and GetPitch.
  663. *
  664. * It also manages mixing Mod Wheel control of pitch and
  665. * volume LFO output. It tracks the scaling of Mod Wheel
  666. * for each of these in m_nMWVolumeScale and m_nMWPitchScale.
  667. * It calls the Mod Wheel module to get the current values
  668. * if the respective scalings are greater than 0.
  669. *
  670. * All of the preset values for the LFO are carried in
  671. * the m_CSource field, which is a replica of the file
  672. * CSourceLFO structure. This is initialized with the
  673. * StartVoice call.
  674. */
  675. class CVoiceLFO
  676. {
  677. public:
  678. CVoiceLFO();
  679. STIME StartVoice(CSourceLFO *pSource,
  680. STIME stStartTime,CModWheelIn * pModWheelIn);
  681. VREL GetVolume( STIME stTime, STIME *pstTime); // Returns volume cents.
  682. PREL GetPitch( STIME stTime, STIME *pstTime); // Returns pitch cents.
  683. private:
  684. long GetLevel( STIME stTime, STIME *pstTime);
  685. CSourceLFO m_Source; // All of the preset information.
  686. STIME m_stStartTime; // Time the voice started playing.
  687. CModWheelIn *m_pModWheelIn; // Pointer to Mod Wheel for this channel.
  688. STIME m_stRepeatTime; // Repeat time for LFO.
  689. };
  690. /*****************************************************************************
  691. * class CVoiceEG
  692. *****************************************************************************
  693. * The CVoiceEG class is used to track the behavior of
  694. * an Envelope Generator within a voice. There are two
  695. * EG's, one for pitch and one for volume. However, they
  696. * behave identically.
  697. *
  698. * All of the preset values for the EG are carried in
  699. * the m_Source field, which is a replica of the file
  700. * CSourceEG structure. This is initialized with the
  701. * StartVoice call.
  702. */
  703. class CVoiceEG
  704. {
  705. public:
  706. CVoiceEG();
  707. STIME StartVoice(CSourceEG *pSource, STIME stStartTime,
  708. WORD nKey, WORD nVelocity);
  709. void StopVoice(STIME stTime);
  710. void QuickStopVoice(STIME stTime, DWORD dwSampleRate);
  711. VREL GetVolume(STIME stTime, STIME *pstTime); // Returns volume cents.
  712. PREL GetPitch(STIME stTime, STIME *pstTime); // Returns pitch cents.
  713. BOOL InAttack(STIME stTime); // is voice still in attack?
  714. BOOL InRelease(STIME stTime); // is voice in release?
  715. private:
  716. long GetLevel(STIME stTime, STIME *pstTime, BOOL fVolume);
  717. CSourceEG m_Source; // Preset values for envelope, copied from file.
  718. STIME m_stStartTime; // Time note turned on
  719. STIME m_stStopTime; // Time note turned off
  720. };
  721. /*****************************************************************************
  722. * class CDigitalAudio
  723. *****************************************************************************
  724. * The CDigitalAudio class is used to track the playback
  725. * of a sample within a voice.
  726. *
  727. * It manages the loop points, the pointer to the sample.
  728. * and the base pitch and base volume, which it initially sets
  729. * when called via StartVoice().
  730. *
  731. * Pitch is stored in a fixed point format, where the leftmost
  732. * 20 bits define the sample increment and the right 12 bits
  733. * define the factional increment within the sample. This
  734. * format is also used to track the position in the sample.
  735. * Mix is a critical routine. It is called by the CVoice to blend
  736. * the instrument into the data buffer. It is handed relative change
  737. * values for pitch and volume (semitone cents and decibel
  738. * cents.) These it converts into three linear values:
  739. * Left volume, Right volume, and Pitch.
  740. *
  741. * It then compares these new values with the values that existed
  742. * for the previous slice and divides by the number of samples to
  743. * determine an incremental change at the sample rate.
  744. * Then, in the critical mix loop, these are added to the
  745. * volume and pitch indices to give a smooth linear slope to the
  746. * change in volume and pitch.
  747. */
  748. #define MAX_SAMPLE 4095
  749. #define MIN_SAMPLE (-4096)
  750. #define MAXDB 0
  751. #define MINDB -100
  752. #define TEST_WRITE_SIZE 3000
  753. #define TEST_SOURCE_SIZE 44100
  754. class CDigitalAudio
  755. {
  756. public:
  757. CDigitalAudio();
  758. STIME StartVoice(CSynth *pSynth,
  759. CSourceSample *pSample,
  760. VREL vrBaseLVolume, VREL vrBaseRVolume,
  761. PREL prBasePitch, long lKey);
  762. BOOL Mix(short *pBuffer,DWORD dwLength,
  763. VREL dwVolumeL, VREL dwVolumeR, PREL dwPitch,
  764. DWORD dwStereo);
  765. void ClearVoice();
  766. static PFRACT PRELToPFRACT(PREL prPitch); // Pitch cents to pitch.
  767. private:
  768. DWORD Mix8(short * pBuffer, DWORD dwLength,DWORD dwDeltaPeriod,
  769. VFRACT vfDeltaLVolume, VFRACT vfDeltaRVolume,
  770. PFRACT pfDeltaPitch,
  771. PFRACT pfSampleLength, PFRACT pfLoopLength);
  772. DWORD MixMono8(short * pBuffer, DWORD dwLength,DWORD dwDeltaPeriod,
  773. VFRACT vfDeltaVolume,
  774. PFRACT pfDeltaPitch,
  775. PFRACT pfSampleLength, PFRACT pfLoopLength);
  776. DWORD Mix16(short * pBuffer, DWORD dwLength, DWORD dwDeltaPeriod,
  777. VFRACT vfDeltaLVolume, VFRACT vfDeltaRVolume,
  778. PFRACT pfDeltaPitch,
  779. PFRACT pfSampleLength, PFRACT pfLoopLength);
  780. DWORD MixMono16(short * pBuffer, DWORD dwLength,DWORD dwDeltaPeriod,
  781. VFRACT vfDeltaVolume,
  782. PFRACT pfDeltaPitch,
  783. PFRACT pfSampleLength, PFRACT pfLoopLength);
  784. DWORD _cdecl Mix8X(short * pBuffer, DWORD dwLength, DWORD dwDeltaPeriod,
  785. VFRACT vfDeltaLVolume, VFRACT vfDeltaRVolume,
  786. PFRACT pfDeltaPitch,
  787. PFRACT pfSampleLength, PFRACT pfLoopLength);
  788. DWORD _cdecl Mix16X(short * pBuffer, DWORD dwLength, DWORD dwDeltaPeriod,
  789. VFRACT vfDeltaLVolume, VFRACT vfDeltaRVolume,
  790. PFRACT pfDeltaPitch,
  791. PFRACT pfSampleLength, PFRACT pfLoopLength);
  792. DWORD MixMono16X(short * pBuffer, DWORD dwLength,DWORD dwDeltaPeriod,
  793. VFRACT vfDeltaVolume,
  794. PFRACT pfDeltaPitch,
  795. PFRACT pfSampleLength, PFRACT pfLoopLength);
  796. DWORD MixMono8X(short * pBuffer, DWORD dwLength,DWORD dwDeltaPeriod,
  797. VFRACT vfDeltaVolume,
  798. PFRACT pfDeltaPitch,
  799. PFRACT pfSampleLength, PFRACT pfLoopLength);
  800. void BeforeBigSampleMix();
  801. void AfterBigSampleMix();
  802. static VFRACT VRELToVFRACT(VREL vrVolume); // dB to absolute.
  803. CSourceSample m_Source; // Preset values for sample.
  804. CSynth * m_pSynth; // For access to sample rate, etc.
  805. BOOL m_fMMXEnabled;
  806. short * m_pnWave; // Private pointer to wave.
  807. VREL m_vrBaseLVolume; // Overall left volume.
  808. VREL m_vrBaseRVolume; // Overall left volume.
  809. PFRACT m_pfBasePitch; // Overall pitch.
  810. VFRACT m_vfLastLVolume; // The last left volume value.
  811. VFRACT m_vfLastRVolume; // The last right volume value.
  812. PFRACT m_pfLastPitch; // The last pitch value.
  813. VREL m_vrLastLVolume; // The last left volume value, in VREL.
  814. VREL m_vrLastRVolume; // Same for right.
  815. PREL m_prLastPitch; // Same for pitch, in PREL.
  816. PFRACT m_pfLastSample; // The last sample position.
  817. PFRACT m_pfLoopStart; // Start of loop.
  818. PFRACT m_pfLoopEnd; // End of loop.
  819. PFRACT m_pfSampleLength; // Length of sample buffer.
  820. BOOL m_fElGrande; // Indicates larger than 1m wave.
  821. ULONGLONG m_ullLastSample; // Used to track > 1m wave.
  822. ULONGLONG m_ullLoopStart; // Used to track > 1m wave.
  823. ULONGLONG m_ullLoopEnd; // Used to track > 1m wave.
  824. ULONGLONG m_ullSampleLength; // Used to track > 1m wave.
  825. DWORD m_dwAddressUpper; // Temp storage for upper bits of address.
  826. };
  827. /*****************************************************************************
  828. * class CVoice
  829. *****************************************************************************
  830. * The CVoice class pulls together everything needed to perform
  831. * one voice. It has the envelopes, lfo, and sample embedded
  832. * within it.
  833. *
  834. * StartVoice() initializes a voice structure for playback. The
  835. * CSourceRegion structure carries the region and sample as well
  836. * as a pointer to the articulation, which is used to set up
  837. * the various articulation modules. It also carries pointers to
  838. * all the MIDI modulation inputs and the values for the note key
  839. * and channel which are used by the parent ControlLogic object
  840. * to match incoming note off events with the right voice.
  841. */
  842. class CVoice : public CListItem
  843. {
  844. public:
  845. CVoice();
  846. CVoice * GetNext()
  847. {return (CVoice *)CListItem::GetNext();};
  848. BOOL StartVoice(CSynth *pControl,
  849. CSourceRegion *pRegion, STIME stStartTime,
  850. CModWheelIn * pModWheelIn,
  851. CPitchBendIn * pPitchBendIn,
  852. CExpressionIn * pExpressionIn,
  853. CVolumeIn * pVolumeIn,
  854. CPanIn * pPanIn,
  855. WORD nKey,WORD nVelocity,
  856. VREL vrVolume, // Added for GS
  857. PREL prPitch); // Added for GS
  858. void StopVoice(STIME stTime); // Called on note off event.
  859. void QuickStopVoice(STIME stTime); // Called to get quick release.
  860. void SpeedRelease(); // Force an already off envelope to release quickly.
  861. void ClearVoice(); // Release use of sample.
  862. PREL GetNewPitch(STIME stTime); // Return current pitch value
  863. void GetNewVolume(STIME stTime, VREL& vrVolume, VREL &vrVolumeR);
  864. // Return current volume value
  865. DWORD Mix(short *pBuffer,DWORD dwLength,STIME stStart,STIME stEnd);
  866. private:
  867. CVoiceLFO m_LFO; // LFO.
  868. CVoiceEG m_PitchEG; // Pitch Envelope.
  869. CVoiceEG m_VolumeEG; // Volume Envelope.
  870. CDigitalAudio m_DigitalAudio; // The Digital Audio Engine structure.
  871. CPitchBendIn * m_pPitchBendIn; // Pitch bend source.
  872. CExpressionIn * m_pExpressionIn; // Expression source.
  873. CVolumeIn * m_pVolumeIn; // Volume source, if allowed to vary
  874. CPanIn * m_pPanIn; // Pan source, if allowed to vary
  875. CSynth * m_pSynth; // To access sample rate, etc.
  876. STIME m_stMixTime; // Next time we need a mix.
  877. long m_lDefaultPan; // Default pan
  878. STIME m_stLastMix; // Last sample position mixed.
  879. public:
  880. STIME m_stStartTime; // Time the sound starts.
  881. STIME m_stStopTime; // Time the sound stops.
  882. BOOL m_fInUse; // This is currently in use.
  883. BOOL m_fNoteOn; // Note is considered on.
  884. BOOL m_fTag; // Used to track note stealing.
  885. VREL m_vrVolume; // Volume, used for voice stealing...
  886. BOOL m_fSustainOn; // Sus pedal kept note on after off event.
  887. WORD m_nPart; // Part that is playing this (channel).
  888. WORD m_nKey; // Note played.
  889. BOOL m_fAllowOverlap; // Allow overlapped note.
  890. DWORD m_dwGroup; // Group this voice is playing now
  891. DWORD m_dwProgram; // Bank and Patch choice.
  892. DWORD m_dwPriority; // Priority.
  893. CControlLogic * m_pControl; // Which control group is playing voice.
  894. };
  895. /*****************************************************************************
  896. * class CVoiceList
  897. *****************************************************************************
  898. * Implements a list of CVoice objects.
  899. */
  900. class CVoiceList : public CList
  901. {
  902. public:
  903. CVoice * GetHead() {return (CVoice *) CList::GetHead();};
  904. CVoice * RemoveHead() {return (CVoice *) CList::RemoveHead();};
  905. CVoice * GetItem(LONG lIndex) {return (CVoice *) CList::GetItem(lIndex);};
  906. };
  907. /*****************************************************************************
  908. * struct PerfStats
  909. *****************************************************************************
  910. * Contains statistics on the synthesizer, updated continuously.
  911. */
  912. typedef struct PerfStats
  913. {
  914. DWORD dwTotalTime;
  915. DWORD dwTotalSamples;
  916. DWORD dwNotesLost;
  917. DWORD dwVoices;
  918. DWORD dwCPU;
  919. DWORD dwMaxAmplitude;
  920. } PerfStats;
  921. #define MIX_BUFFER_LEN 500 // Set the sample buffer size to 500 mils
  922. #define MAX_NUM_VOICES 32
  923. #define NUM_EXTRA_VOICES 8 // Extra voices for when we overload.
  924. /*****************************************************************************
  925. * class CControlLogic
  926. *****************************************************************************
  927. * CControlLogic object, implementing the control logic for the DLS
  928. * instrument. This handles MIDI events, plus selection of instrument, sample
  929. * and articulation.
  930. *
  931. *
  932. * Essentially, ControlLogic is the big Kahuna that manages
  933. * the whole system. It parses incoming MIDI events
  934. * by channel and event type. And, it manages the mixing
  935. * of voices into the buffer.
  936. *
  937. * MIDI Input:
  938. *
  939. * The most important events are the note on and
  940. * off events. When a note on event comes in,
  941. * ControlLogic searches for an available voice.
  942. * ControlLogic matches the channel and finds the
  943. * instrument on that channel. It then call the instrument's
  944. * ScanForRegion() command which finds the region
  945. * that matches the note. At this point, it can copy
  946. * the region and associated articulation into the
  947. * voice, using the StartVoice command.
  948. *
  949. * When it receives the sustain pedal command,
  950. * it artificially sets all notes on the channel on
  951. * until a sustain off arrives. To keep track of notes
  952. * that have been shut off while the sustain was on
  953. * it uses an array of 128 shorts, with each bit position
  954. * representing a channel. When the sustain releases,
  955. * it scans through the array and creates a note off for
  956. * each bit that was set.
  957. *
  958. * Additional continuous controller events are managed
  959. * by the CModWheelIn, CPitchBendIn, etc., MIDI input recording
  960. * modules.
  961. *
  962. * Mixing:
  963. *
  964. * Control Logic is also called to mix the instruments into a buffer
  965. * at regular intervals. The buffer is provided by the calling sound
  966. * driver. Each voice is called to mix its sample into the buffer.
  967. */
  968. class CControlLogic
  969. {
  970. public:
  971. CControlLogic();
  972. ~CControlLogic();
  973. HRESULT Init(CInstManager *pInstruments, CSynth *pSynth);
  974. void Flush(STIME stTime); // Clears all events after time.
  975. BOOL RecordMIDI(STIME stTime,BYTE bStatus, BYTE bData1, BYTE bData2);
  976. HRESULT RecordSysEx(DWORD dwSysExLength,BYTE *pSysExData, STIME stTime);
  977. void QueueNotes(STIME stEndTime);
  978. void ClearMIDI(STIME stEndTime);
  979. void SetGainAdjust(VREL vrGainAdjust);
  980. HRESULT SetChannelPriority(DWORD dwChannel,DWORD dwPriority);
  981. HRESULT GetChannelPriority(DWORD dwChannel,LPDWORD pdwPriority);
  982. CSynth * m_pSynth;
  983. private:
  984. void GMReset();
  985. CInstManager * m_pInstruments;
  986. CNoteIn m_Notes; // All Note ons and offs.
  987. CModWheelIn m_ModWheel[16]; // Sixteen channels of Mod Wheel.
  988. CPitchBendIn m_PitchBend[16]; // Sixteen channels of Pitch Bend.
  989. CVolumeIn m_Volume[16]; // Sixteen channels of Volume.
  990. CExpressionIn m_Expression[16]; // Sixteen channels of Expression.
  991. CPanIn m_Pan[16]; // Sixteen channels of Pan.
  992. BOOL m_fSustain[16]; // Sustain on / off.
  993. short m_nCurrentRPN[16]; // RPN number.
  994. BYTE m_bBankH[16]; // Bank selects for instrument.
  995. BYTE m_bBankL[16];
  996. DWORD m_dwProgram[16]; // Instrument choice.
  997. BOOL m_fEmpty; // Indicates empty lists, no need to flush.
  998. VREL m_vrGainAdjust; // Final stage gain adjust
  999. DWORD m_dwPriority[16]; // Priorities for each channel.
  1000. BOOL m_fXGActive; // Is XG Active?
  1001. BOOL m_fGSActive; // Is GS enabled?
  1002. WORD m_nData[16]; // Used to track RPN reading.
  1003. VREL m_vrMasterVolume; // Master Volume.
  1004. PREL m_prFineTune[16]; // Fine tune for each channel.
  1005. PREL m_prScaleTune[16][12];// Alternate scale for each channel.
  1006. PREL m_prCoarseTune[16]; // Coarse tune.
  1007. BYTE m_bPartToChannel[16]; // Channel to Part converter.
  1008. BYTE m_bDrums[16]; // Melodic or which drum?
  1009. BOOL m_fMono[16]; // Mono mode?
  1010. public:
  1011. CRITICAL_SECTION m_CriticalSection; // Critical section to manage access.
  1012. BOOL m_fCSInitialized;
  1013. };
  1014. #endif // __SYNTH_H__