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.

1490 lines
57 KiB

  1. // Synth.h
  2. // Copyright (c) 1996-1999 Microsoft Corporation
  3. //
  4. /* For internal representation, volume is stored in Volume Cents,
  5. where each increment represents 1/100 of a dB.
  6. Pitch is stored in Pitch Cents, where each increment
  7. represents 1/100 of a semitone.
  8. */
  9. #ifndef __SYNTH_H__
  10. #define __SYNTH_H__
  11. #pragma warning(disable:4296)
  12. #include "clist.h"
  13. #include "dmdls.h"
  14. #include "dls2.h"
  15. #include "dsound.h"
  16. #include "dmusicc.h"
  17. #ifdef DBG
  18. extern DWORD sdwDebugLevel;
  19. #endif
  20. #define MIDI_NOTEOFF 0x80
  21. #define MIDI_NOTEON 0x90
  22. #define MIDI_PTOUCH 0xA0
  23. #define MIDI_CCHANGE 0xB0
  24. #define MIDI_PCHANGE 0xC0
  25. #define MIDI_MTOUCH 0xD0
  26. #define MIDI_PBEND 0xE0
  27. #define MIDI_SYSX 0xF0
  28. #define MIDI_MTC 0xF1
  29. #define MIDI_SONGPP 0xF2
  30. #define MIDI_SONGS 0xF3
  31. #define MIDI_EOX 0xF7
  32. #define MIDI_CLOCK 0xF8
  33. #define MIDI_START 0xFA
  34. #define MIDI_CONTINUE 0xFB
  35. #define MIDI_STOP 0xFC
  36. #define MIDI_SENSE 0xFE
  37. // controller numbers
  38. #define CC_BANKSELECTH 0x00
  39. #define CC_BANKSELECTL 0x20
  40. #define CC_MODWHEEL 0x01
  41. #define CC_VOLUME 0x07
  42. #define CC_PAN 0x0A
  43. #define CC_EXPRESSION 0x0B
  44. #define CC_SUSTAIN 0x40
  45. #define CC_CUTOFFFREQ 0x4A
  46. #define CC_REVERB 0x5B
  47. #define CC_CHORUS 0x5D
  48. #define CC_ALLSOUNDSOFF 0x78
  49. #define CC_RESETALL 0x79
  50. #define CC_ALLNOTESOFF 0x7B
  51. #define CC_MONOMODE 0x7E
  52. #define CC_POLYMODE 0x7F
  53. // rpn controllers
  54. #define CC_DATAENTRYMSB 0x06
  55. #define CC_DATAENTRYLSB 0x26
  56. #define CC_NRPN_LSB 0x62
  57. #define CC_NRPN_MSB 0x63
  58. #define CC_RPN_LSB 0x64
  59. #define CC_RPN_MSB 0x65
  60. // registered parameter numbers
  61. #define RPN_PITCHBEND 0x00
  62. #define RPN_FINETUNE 0x01
  63. #define RPN_COARSETUNE 0x02
  64. /* Sample format and Sample playback flags are organized
  65. together because together they determine which
  66. mix loop to use.
  67. */
  68. #define SFORMAT_16 1 // Sixteen bit sample.
  69. #define SFORMAT_8 2 // Eight bit sample.
  70. #define SPLAY_MMX 0x10 // Use MMX processor (16 bit only).
  71. #define SPLAY_INTERLEAVED 0x40 // Interleave Buffer
  72. #define SPLAY_FILTERED 0x80 // Non-trivial filter coeff's
  73. /* Output buffer format flags, defines whether the buffers being
  74. played are multi-buffer, interleave or just plain mono
  75. */
  76. #define BUFFERFLAG_MONO 0x00000000
  77. #define BUFFERFLAG_INTERLEAVED 0x00000001
  78. #define BUFFERFLAG_MULTIBUFFER 0x00000002
  79. typedef long PREL; // Pitch cents, for relative pitch.
  80. typedef short PRELS; // Pitch cents, in storage form.
  81. typedef long VREL; // Volume cents, for relative volume.
  82. typedef short VRELS; // Volume cents, in storage form.
  83. typedef long TREL; // Time cents, for relative time
  84. typedef short TRELS; // Time Cents, in storage form.
  85. typedef LONGLONG STIME; // Time value, in samples.
  86. typedef long MTIME; // Time value, in milliseconds.
  87. typedef long PFRACT; // Pitch increment, where upper 20 bits are
  88. // the index and the lower 12 are the fractional
  89. // component.
  90. typedef long VFRACT; // Volume, where lower 12 bits are the fraction.
  91. typedef long TCENT;
  92. typedef short SPERCENT;
  93. #define COEFF_UNITY 0x40000000 // 1.0 multiplier as a 2.30 number
  94. typedef unsigned long COEFF; // 2.30 fixed point filter coefficient
  95. typedef long COEFFDELTA; // 2.30 fixed point filter coefficient delta value
  96. #define FILTER_PARMS_DIM_Q 16 // the number of different resonances in the filter parameter table (rows)
  97. #define FILTER_PARMS_DIM_FC 89 // the number of different cutoff frequencies in the filter parameter table (cols)
  98. #define FILTER_FREQ_RANGE 10688 // the difference in pitch cents between the sample rate of the filter design and the
  99. #define MAX_VOLUME 0 // No attenuation and no amplification
  100. #define MIN_VOLUME -9600 // Below 96 db down is considered off.
  101. #define PERCEIVED_MIN_VOLUME -8000 // But, we cheat.
  102. #define SAMPLE_RATE_22 22050 // 22 kHz is the standard rate.
  103. #define SAMPLE_RATE_44 44100 // 44 kHz is the high quality rate.
  104. #define SAMPLE_RATE_11 11025 // 11 kHz should not be allowed!
  105. #define STEREO_ON 1
  106. #define STEREO_OFF 0
  107. #define MAX_DAUD_CHAN 32
  108. #define FORCEBOUNDS(data,min,max) {if (data < min) data = min; else if (data > max) data = max;}
  109. class CControlLogic;
  110. /*
  111. >>>>>>>>> comment
  112. */
  113. class CBusIds
  114. {
  115. public:
  116. CBusIds();
  117. ~CBusIds();
  118. HRESULT Initialize();
  119. HRESULT AssignBuses(LPDWORD pdwBusIds, DWORD dwBusCount);
  120. public:
  121. DWORD m_dwBusCount; // Number of Bus Id's
  122. DWORD m_dwBusIds[MAX_DAUD_CHAN]; // Array of bus IDs
  123. };
  124. /* CSourceLFO is the file format definition of the LFO in an
  125. instrument. This is used to represent an LFO as part of
  126. a specific articulation set within an instrument that
  127. has been loaded from disk. Once the instrument is chosen
  128. to play a note, this is also copied into the CVoice
  129. object.
  130. */
  131. class CSourceLFO
  132. {
  133. public:
  134. CSourceLFO();
  135. void Init(DWORD dwSampleRate);
  136. void SetSampleRate(long lDirection);
  137. void Verify(); // Verifies that the data is valid.
  138. PFRACT m_pfFrequency; // Frequency, in increments through the sine table.
  139. STIME m_stDelay; // How long to delay in sample units.
  140. VRELS m_vrMWVolumeScale; // Scaling of volume LFO by Mod Wheel.
  141. PRELS m_prMWPitchScale; // Scaling of pitch LFO by Mod Wheel.
  142. VRELS m_vrVolumeScale; // Scaling of straight volume signal from LFO.
  143. PRELS m_prPitchScale; // Scaling of straight pitch signal from LFO.
  144. /* DirectX8 members */
  145. PRELS m_prCPPitchScale; // Scaling of pitch signal from channel pressure.
  146. VRELS m_vrCPVolumeScale; // Scaling of volume signal from channel pressure.
  147. //>>>>>>>> comments
  148. PRELS m_prCutoffScale; // Scaling of Cutoff feq >>>>>>
  149. PRELS m_prMWCutoffScale; // Scaling of Cutoff feq mod wheel
  150. PRELS m_prCPCutoffScale; // Scaling of Cutoff feq channel pressure
  151. };
  152. /* CSourceEG is the file format definition of an Envelope
  153. generator in an instrument.
  154. */
  155. class CSourceEG
  156. {
  157. public:
  158. CSourceEG();
  159. void SetSampleRate(long lDirection);
  160. void Init();
  161. void Verify(); // Verifies valid data.
  162. STIME m_stAttack; // Attack rate.
  163. STIME m_stDecay; // Decay rate.
  164. STIME m_stRelease; // Release rate.
  165. TRELS m_trVelAttackScale; // Scaling of attack by note velocity.
  166. TRELS m_trKeyDecayScale; // Scaling of decay by note value.
  167. SPERCENT m_pcSustain; // Sustain level.
  168. short m_sScale; // Scaling of entire signal.
  169. /* DLS2 */
  170. STIME m_stDelay; // Delay rate.
  171. STIME m_stHold; // Hold rate.
  172. TRELS m_trKeyHoldScale; // Scaling of Hold by note value.
  173. //>>>>>>>> comments
  174. PRELS m_prCutoffScale; // Scaling of Cutoff feq >>>>>>
  175. };
  176. //>>>>>>>> comments
  177. class CSourceFilter
  178. {
  179. public:
  180. CSourceFilter();
  181. void SetSampleRate(long lDirection);
  182. void Init(DWORD dwSampleRate);
  183. void Verify();
  184. PRELS m_prSampleRate; // Sample rate in cents
  185. PRELS m_prCutoff; // Cutoff Frequency in absolute pitch
  186. PRELS m_prCutoffSRAdjust; // Cutoff Frequency adjusted to the sampel rate
  187. VRELS m_vrQ; // Resonance
  188. DWORD m_iQIndex; // Q index
  189. PRELS m_prVelScale; // Scale by key velocity
  190. PRELS m_prKeyScale; // Scaling by note value.
  191. };
  192. /* CSourceArticulation is the file format definition of
  193. a complete articulation set: the LFO and two
  194. envelope generators.
  195. Since several regions within one Instrument can
  196. share one articulation, a counter is used to keep
  197. track of the usage.
  198. */
  199. class CSourceArticulation
  200. {
  201. public:
  202. CSourceArticulation();
  203. HRESULT Download(DMUS_DOWNLOADINFO * pInfo,
  204. void * pvOffsetTable[], DWORD dwIndex,
  205. DWORD dwSampleRate, BOOL fNewFormat);
  206. #ifdef DDUMP
  207. void Dump(DWORD dwIndent,DWORD dwLevel);
  208. #endif
  209. void Init(DWORD dwSampleRate);
  210. void Verify(); // Verifies valid data.
  211. void AddRef();
  212. void Release();
  213. void SetSampleRate(DWORD dwSampleRate);
  214. CSourceEG m_PitchEG; // Pitch envelope.
  215. CSourceEG m_VolumeEG; // Volume envelope.
  216. CSourceLFO m_LFO; // Low frequency oscillator.
  217. DWORD m_dwSampleRate;
  218. WORD m_wUsageCount; // Keeps track of how many times in use.
  219. short m_sDefaultPan; // default pan (for drums)
  220. /* DLS2 */
  221. CSourceLFO m_LFO2; // Vibrato
  222. CSourceFilter m_Filter; // Low pass filter
  223. };
  224. /* Since multiple regions may reference
  225. the same Wave, a reference count is maintained to
  226. keep track of how many regions are using the sample.
  227. */
  228. class CWave : public CListItem
  229. {
  230. public:
  231. CWave();
  232. ~CWave();
  233. #ifdef DDUMP
  234. void Dump(DWORD dwIndent,DWORD dwLevel);
  235. #endif
  236. void Verify(); // Verifies that the data is valid.
  237. void Release(); // Remove reference.
  238. void AddRef(); // Add reference.
  239. void PlayOn(); // Increment play count.
  240. void PlayOff(); // Decrement play count.
  241. BOOL IsPlaying(); // Is currently playing?
  242. CWave * GetNext() {return(CWave *)CListItem::GetNext();};
  243. DWORD m_dwSampleLength; // Length of sample.
  244. DWORD m_dwSampleRate;
  245. HRESULT ( CALLBACK *m_lpFreeHandle)(HANDLE,HANDLE);
  246. HANDLE m_hUserData; // Used to notify app when wave released.
  247. short * m_pnWave;
  248. DWORD m_dwID; // ID for matching wave with regions.
  249. WORD m_wUsageCount; // Keeps track of how many times in use.
  250. WORD m_wPlayCount; // Wave is currently being played.
  251. BYTE m_bSampleType;
  252. /* DirectX 8 members */
  253. BYTE m_bStream; // This wave is used as a streaming buffer
  254. BYTE m_bActive; // This buffer is currently be used to play out of
  255. BYTE m_bValid; // Indicates data in the buffer is valid
  256. BYTE m_bLastSampleInit; // Indicates the the buffers last sample has been initialize
  257. };
  258. class CWavePool : public CList
  259. {
  260. public:
  261. CWave * GetHead() {return (CWave *)CList::GetHead();};
  262. CWave * GetItem(DWORD dwID) {return (CWave *)CList::GetItem((LONG)dwID);};
  263. CWave * RemoveHead() {return (CWave *)CList::RemoveHead();};
  264. };
  265. /* The CSourceSample class describes one sample in an
  266. instrument. The sample is referenced by a CSourceRegion
  267. structure.
  268. */
  269. class Collection;
  270. class CSourceSample
  271. {
  272. public:
  273. CSourceSample();
  274. ~CSourceSample();
  275. BOOL CopyFromWave();
  276. void Verify(); // Verifies that the data is valid.
  277. CWave * m_pWave; // Wave in pool.
  278. DWORD m_dwLoopStart; // Index of start of loop.
  279. DWORD m_dwLoopEnd; // Index of end of loop.
  280. DWORD m_dwSampleLength; // Length of sample.
  281. DWORD m_dwSampleRate; // Sample rate of recording.
  282. PRELS m_prFineTune; // Fine tune to correct pitch.
  283. DWORD m_dwID; // Wave pool id.
  284. BYTE m_bSampleType; // 16 or 8.
  285. BYTE m_bOneShot; // Is this a one shot sample?
  286. BYTE m_bMIDIRootKey; // MIDI note number for sample.
  287. DWORD m_dwLoopType; // WLOOP_TYPE_xxx
  288. };
  289. /* The CSourceRegion class defines a region within an instrument.
  290. The sample is managed with a pointer instead of an embedded
  291. sample. This allows multiple regions to use the same
  292. sample.
  293. Each region also has an associated articulation. For drums, there
  294. is a one to one matching. For melodic instruments, all regions
  295. share the same articulation. So, to manage this, each region
  296. points to the articulation.
  297. */
  298. class CSourceRegion : public CListItem
  299. {
  300. public:
  301. CSourceRegion();
  302. ~CSourceRegion();
  303. #ifdef DDUMP
  304. void Dump(DWORD dwIndent,DWORD dwLevel);
  305. #endif
  306. CSourceRegion *GetNext() {return(CSourceRegion *)CListItem::GetNext();};
  307. void Verify(); // Verifies that the data is valid.
  308. void SetSampleRate(DWORD dwSampleRate);
  309. HRESULT Download(DMUS_DOWNLOADINFO * pInfo, void * pvOffsetTable[],
  310. DWORD *pdwRegionIX, DWORD dwSampleRate, BOOL fNewFormat);
  311. CSourceSample m_Sample; // Sample structure.
  312. CSourceArticulation * m_pArticulation; // Pointer to associated articulation.
  313. VRELS m_vrAttenuation; // Volume change to apply to sample.
  314. PRELS m_prTuning; // Pitch shift to apply to sample.
  315. BYTE m_bAllowOverlap; // Allow overlapping of note.
  316. BYTE m_bKeyHigh; // Upper note value for region.
  317. BYTE m_bKeyLow; // Lower note value.
  318. BYTE m_bGroup; // Logical group (for drums.)
  319. /* DLS2 */
  320. BYTE m_bVelocityHigh; // Upper velocity value for region.
  321. BYTE m_bVelocityLow; // Lower velocity value.
  322. SHORT m_sWaveLinkOptions; // Wave link chunk option flags
  323. DWORD m_dwChannel; // Region channels, from WAVELINK chunk
  324. // Channel in m_dwChannel provides voice destination and overrides anything
  325. // from the articulation.
  326. //
  327. inline BOOL IsMultiChannel() const
  328. { return (BOOL)(m_sWaveLinkOptions & F_WAVELINK_MULTICHANNEL); }
  329. };
  330. class CSourceRegionList : public CList
  331. {
  332. public:
  333. CSourceRegion *GetHead() {return (CSourceRegion *)CList::GetHead();};
  334. CSourceRegion *RemoveHead() {return (CSourceRegion *)CList::RemoveHead();};
  335. };
  336. /* The CInstrument class is really the file format definition
  337. of an instrument.
  338. The CInstrument can be either a Drum or a Melodic instrument.
  339. If a drum, it has up to 128 pairings of articulations and
  340. regions. If melodic, all regions share the same articulation.
  341. ScanForRegion is called by ControlLogic to get the region
  342. that corresponds to a note.
  343. */
  344. class CInstManager;
  345. class CInstrument : public CListItem
  346. {
  347. public:
  348. CInstrument();
  349. ~CInstrument();
  350. #ifdef DDUMP
  351. void Dump(DWORD dwIndent,DWORD dwLevel);
  352. #endif
  353. void Init(DWORD dwSampleRate);
  354. void Verify(); // Verifies that the data is valid.
  355. CInstrument * GetInstrument(DWORD dwProgram,DWORD dwAccept);
  356. CInstrument * GetNext() {return(CInstrument *)CListItem::GetNext();};
  357. void SetSampleRate(DWORD dwSampleRate);
  358. CSourceRegion * ScanForRegion(DWORD dwNoteValue, DWORD dwVelocity, CSourceRegion *pRegion = NULL);
  359. CSourceRegionList m_RegionList; // Linked list of regions.
  360. DWORD m_dwProgram; // Which program change it represents.
  361. HRESULT LoadRegions( BYTE *p, BYTE *pEnd, DWORD dwSampleRate);
  362. HRESULT Load( BYTE *p, BYTE *pEnd, DWORD dwSampleRate);
  363. };
  364. class CInstrumentList : public CList
  365. {
  366. public:
  367. CInstrument * GetHead() {return (CInstrument *)CList::GetHead();};
  368. CInstrument * RemoveHead() {return (CInstrument *)CList::RemoveHead();};
  369. };
  370. class CWaveBufferList;
  371. class CWaveBuffer : public CListItem
  372. {
  373. friend CWaveBufferList;
  374. public:
  375. CWaveBuffer()
  376. {
  377. }
  378. CWaveBuffer * GetNext() { return (CWaveBuffer *)CListItem::GetNext();};
  379. CWaveBuffer * GetNextLoop()
  380. {
  381. // Threat the list as a circular list
  382. CWaveBuffer *pbuf;
  383. pbuf = (CWaveBuffer *)CListItem::GetNext();
  384. if ( pbuf == NULL )
  385. pbuf = (CWaveBuffer *)*m_ppHead;
  386. return pbuf;
  387. };
  388. CWave * m_pWave; // pointer to wave object
  389. protected:
  390. CListItem** m_ppHead;
  391. };
  392. class CWaveBufferList : public CList
  393. {
  394. public:
  395. CWaveBuffer *GetHead() {return (CWaveBuffer *)CList::GetHead();};
  396. CWaveBuffer *RemoveHead() {return (CWaveBuffer *)CList::RemoveHead();};
  397. // Overide these methods so that m_pHead can be added to CWaveBuffer ListItem
  398. // to allow GetNextLoop() to function as a simple circular buffer list
  399. void InsertBefore(CListItem *pItem,CWaveBuffer *pInsert) {pInsert->m_ppHead = &m_pHead; CList::Cat(pItem);};
  400. void Cat(CWaveBuffer *pItem) {pItem->m_ppHead = &m_pHead; CList::Cat(pItem);};
  401. void AddHead(CWaveBuffer *pItem) {pItem->m_ppHead = &m_pHead; CList::AddHead(pItem);};
  402. void AddTail(CWaveBuffer *pItem) {pItem->m_ppHead = &m_pHead; CList::AddTail(pItem);};
  403. };
  404. class CWaveArt : public CListItem
  405. {
  406. public:
  407. CWaveArt();
  408. ~CWaveArt();
  409. void Release(); // Remove reference.
  410. void AddRef(); // Add reference.
  411. void Verify(); // Verifies that the data is valid.
  412. CWaveArt * GetNext() {return(CWaveArt *)CListItem::GetNext();};
  413. DWORD m_dwID; // ID for matching wave with regions.
  414. DMUS_WAVEARTDL m_WaveArtDl;
  415. WAVEFORMATEX m_WaveformatEx;
  416. CWaveBufferList m_pWaves; // Array of Wave buffers associated with dowload id's
  417. // DWORD m_dwSampleLength;
  418. BYTE m_bSampleType;
  419. BOOL m_bStream; // Is this a streaming articulation
  420. WORD m_wUsageCount; // Keeps track of how many times in use.
  421. };
  422. class CWaveArtList : public CList
  423. {
  424. public:
  425. CWaveArt * GetHead() {return (CWaveArt *)CList::GetHead();};
  426. CWaveArt * RemoveHead() {return (CWaveArt *)CList::RemoveHead();};
  427. };
  428. #define WAVE_HASH_SIZE 31 // Keep waves in a hash table of linked lists to speed access.
  429. #define INSTRUMENT_HASH_SIZE 31 // Same with instruments.
  430. #define WAVEART_HASH_SIZE 31
  431. class CInstManager {
  432. public:
  433. CInstManager();
  434. ~CInstManager();
  435. #ifdef DDUMP
  436. void Dump(DWORD dwIndent,DWORD dwLevel);
  437. #endif
  438. CInstrument * GetInstrument(DWORD dwPatch,DWORD dwKey,DWORD dwVelocity);
  439. void Verify(); // Verifies that the data is valid.
  440. void SetSampleRate(DWORD dwSampleRate);
  441. HRESULT Download(LPHANDLE phDownload,
  442. void * pvData,
  443. LPBOOL pbFree);
  444. HRESULT Unload(HANDLE hDownload,
  445. HRESULT ( CALLBACK *lpFreeHandle)(HANDLE,HANDLE),
  446. HANDLE hUserData);
  447. /* DirectX8 Methods */
  448. CWave * GetWave(DWORD dwDLId);
  449. CWaveArt * GetWaveArt(DWORD dwDLId);
  450. private:
  451. HRESULT DownloadInstrument(LPHANDLE phDownload,
  452. DMUS_DOWNLOADINFO *pInfo,
  453. void *pvOffsetTable[],
  454. void *pvData,
  455. BOOL fNewFormat);
  456. HRESULT DownloadWave(LPHANDLE phDownload,
  457. DMUS_DOWNLOADINFO *pInfo,
  458. void *pvOffsetTable[],
  459. void *pvData);
  460. /* DirectX8 Private Methods */
  461. HRESULT DownloadWaveArticulation(LPHANDLE phDownload,
  462. DMUS_DOWNLOADINFO *pInfo,
  463. void *pvOffsetTable[],
  464. void *pvData);
  465. HRESULT DownloadWaveRaw(LPHANDLE phDownload,
  466. DMUS_DOWNLOADINFO *pInfo,
  467. void *pvOffsetTable[],
  468. void *pvData);
  469. CInstrumentList m_InstrumentList[INSTRUMENT_HASH_SIZE];
  470. CWavePool m_WavePool[WAVE_HASH_SIZE];
  471. CWavePool m_FreeWavePool; // Track waves still in use, but unloaded.
  472. DWORD m_dwSampleRate; // Sample rate requested by app.
  473. /* DirectX8 Private Memmebers */
  474. CWaveArtList m_WaveArtList[WAVEART_HASH_SIZE];
  475. public:
  476. DWORD m_dwSynthMemUse; /* Memory used by synth wave data */
  477. CRITICAL_SECTION m_CriticalSection; // Critical section to manage access.
  478. BOOL m_fCSInitialized;
  479. };
  480. /* CMIDIRecorder is used to keep track of a time
  481. slice of MIDI continuous controller events.
  482. This is subclassed by the PitchBend, Volume,
  483. Expression, and ModWheel Recorder classes, so
  484. each of them may reliably manage MIDI events
  485. coming in.
  486. CMIDIRecorder uses a linked list of CMIDIData
  487. structures to keep track of the changes within
  488. the time slice.
  489. Allocation and freeing of the CMIDIData events
  490. is kept fast and efficient because they are
  491. always pulled from the static pool m_pFreeList,
  492. which is really a list of events pulled directly
  493. from the static array m_sEventBuffer. This is
  494. safe because we can make the assumption that
  495. the maximum MIDI rate is 1000 events per second.
  496. Since we are managing time slices of roughly
  497. 1/16 of a second, a buffer of 100 events would
  498. be overkill.
  499. Although CMIDIRecorder is subclassed to several
  500. different event types, they all share the one
  501. staticly declared free list.
  502. */
  503. class CMIDIData : public CListItem
  504. {
  505. public:
  506. CMIDIData();
  507. CMIDIData * GetNext() {return (CMIDIData *)CListItem::GetNext();};
  508. STIME m_stTime; // Time this event was recorded.
  509. long m_lData; // Data stored in event.
  510. };
  511. class CMIDIDataList : public CList
  512. {
  513. public:
  514. CMIDIData *GetHead() {return (CMIDIData *)CList::GetHead();};
  515. CMIDIData *RemoveHead() {return (CMIDIData *)CList::RemoveHead();};
  516. };
  517. class CMIDIRecorder
  518. {
  519. public:
  520. CMIDIRecorder();
  521. ~CMIDIRecorder(); // Be sure to clear local list.
  522. BOOL FlushMIDI(STIME stTime); // Clear after time stamp.
  523. BOOL ClearMIDI(STIME stTime); // Clear up to time stamp.
  524. BOOL RecordMIDI(STIME stTime, long lData); // MIDI input goes here.
  525. BOOL RecordMIDINote(STIME stTime, long lData); // MIDI input goes here.
  526. long GetData(STIME stTime); // Gets data at time.
  527. static VREL VelocityToVolume(WORD nVelocity);
  528. protected:
  529. static VREL m_vrMIDIToVREL[128]; // Array for converting MIDI to volume.
  530. static VREL m_vrMIDIPercentToVREL[128]; // Array for converting MIDI reverb and chorus percentages to volume.
  531. private:
  532. static DWORD m_sUsageCount; // Keeps track of how many instances so free list can be released.
  533. public:
  534. static CMIDIDataList m_sFreeList; // Global free list of events.
  535. protected:
  536. CMIDIDataList m_EventList; // This recorder's list.
  537. STIME m_stCurrentTime; // Time for current value.
  538. long m_lCurrentData; // Current value.
  539. };
  540. class CNote {
  541. public:
  542. STIME m_stTime;
  543. BYTE m_bPart;
  544. BYTE m_bKey;
  545. BYTE m_bVelocity;
  546. };
  547. // Fake note values held in CNoteIn's queue
  548. // to indicate changes in the sustain pedal
  549. // and "all notes off".
  550. // This is a grab bag for synchronous events
  551. // that should be queued in time, not simply done as
  552. // soon as received.
  553. // By putting them in the note queue, we ensure
  554. // they are evaluated in the exact same order as
  555. // the notes themselves.
  556. const BYTE NOTE_PROGRAMCHANGE = 0xF1;
  557. const BYTE NOTE_CC_BANKSELECTH = 0xF2;
  558. const BYTE NOTE_CC_BANKSELECTL = 0xF3;
  559. const BYTE NOTE_CC_POLYMODE = 0xF4;
  560. const BYTE NOTE_CC_MONOMODE = 0xF5;
  561. const BYTE NOTE_CC_RPN_MSB = 0xF6;
  562. const BYTE NOTE_CC_RPN_LSB = 0xF7;
  563. const BYTE NOTE_CC_NRPN = 0xF8;
  564. const BYTE NOTE_CC_DATAENTRYLSB = 0xF9;
  565. const BYTE NOTE_CC_DATAENTRYMSB = 0xFA;
  566. const BYTE NOTE_ASSIGNRECEIVE = 0xFB;
  567. const BYTE NOTE_MASTERVOLUME = 0xFC;
  568. const BYTE NOTE_SOUNDSOFF = 0xFD;
  569. const BYTE NOTE_SUSTAIN = 0xFE;
  570. const BYTE NOTE_ALLOFF = 0xFF;
  571. class CNoteIn : public CMIDIRecorder
  572. {
  573. public:
  574. void FlushMIDI(STIME stTime);
  575. void FlushPart(STIME stTime, BYTE bChannel);
  576. BOOL RecordNote(STIME stTime, CNote * pNote);
  577. BOOL RecordEvent(STIME stTime, DWORD dwPart, DWORD dwCommand, BYTE bData);
  578. BOOL GetNote(STIME stTime, CNote * pNote); // Gets the next note.
  579. };
  580. /* CModWheelIn handles one channel of Mod Wheel
  581. input. As such, it is not embedded in the CVoice
  582. class, rather it is in the Channel class.
  583. CModWheelIn's task is simple: keep track of MIDI
  584. Mod Wheel events, each tagged with millisecond
  585. time and value, and return the value for a specific
  586. time request.
  587. CModWheelIn inherits almost all of its functionality
  588. from the CMIDIRecorder Class.
  589. CModWheelIn receives MIDI mod wheel events through
  590. the RecordMIDI() command, which stores the
  591. time and value of the event.
  592. CModWheelIn is called by CVoiceLFO to get the
  593. current values for the mod wheel to set the amount
  594. of LFO modulation for pitch and volume.
  595. */
  596. class CModWheelIn : public CMIDIRecorder
  597. {
  598. public:
  599. DWORD GetModulation(STIME stTime); // Gets the current Mod Wheel value.
  600. };
  601. /* CPitchBendIn handles one channel of Pitch Bend
  602. input. Like the Mod Wheel module, it inherits
  603. its abilities from the CMIDIRecorder class.
  604. It has one additional routine, GetPitch(),
  605. which returns the current pitch bend value.
  606. */
  607. class CPitchBendIn : public CMIDIRecorder
  608. {
  609. public:
  610. CPitchBendIn();
  611. PREL GetPitch(STIME stTime); // Gets the current pitch in pitch cents.
  612. // current pitch bend range. Note that this is not timestamped!
  613. PREL m_prRange;
  614. };
  615. /* CVolumeIn handles one channel of Volume
  616. input. It inherits its abilities from
  617. the CMIDIRecorder class.
  618. It has one additional routine, GetVolume(),
  619. which returns the volume in decibels at the
  620. specified time.
  621. */
  622. class CVolumeIn : public CMIDIRecorder
  623. {
  624. public:
  625. CVolumeIn();
  626. VREL GetVolume(STIME stTime); // Gets the current volume in db cents.
  627. };
  628. /* CExpressionIn handles one channel of Expression
  629. input. It inherits its abilities from
  630. the CMIDIRecorder class.
  631. It has one additional routine, GetVolume(),
  632. which returns the volume in decibels at the
  633. specified time.
  634. */
  635. class CExpressionIn : public CMIDIRecorder
  636. {
  637. public:
  638. CExpressionIn();
  639. VREL GetVolume(STIME stTime); // Gets the current volume in db cents.
  640. };
  641. /* CPanIn handles one channel of Volume
  642. input. It inherits its abilities from
  643. the CMIDIRecorder class.
  644. It has one additional routine, GetPan(),
  645. which returns the pan position (MIDI value)
  646. at the specified time.
  647. */
  648. class CPanIn : public CMIDIRecorder
  649. {
  650. public:
  651. CPanIn();
  652. long GetPan(STIME stTime); // Gets the current pan.
  653. };
  654. /* CProgramIn handles one channel of Program change
  655. input. It inherits its abilities from
  656. the CMIDIRecorder class.
  657. Unlike the other controllers, it actually
  658. records a series of bank select and program
  659. change events, so it's job is a little
  660. more complex. Three routines handle the
  661. recording of the three different commands (bank 1,
  662. bank 2, program change).
  663. */
  664. /*class CProgramIn : public CMIDIRecorder
  665. {
  666. public:
  667. CProgramIn();
  668. DWORD GetProgram(STIME stTime); // Gets the current program change.
  669. BOOL RecordBankH(BYTE bBank1);
  670. BOOL RecordBankL(BYTE bBank2);
  671. BOOL RecordProgram(STIME stTime, BYTE bProgram);
  672. private:
  673. BYTE m_bBankH;
  674. BYTE m_bBankL;
  675. };*/
  676. /* CPressureIn handles one channel of Channel Pressure
  677. input. As such, it is not embedded in the CVoice
  678. class, rather it is in the Channel class.
  679. CPressureIn's task is simple: keep track of MIDI
  680. Channel Pressure events, each tagged with millisecond
  681. time and value, and return the value for a specific
  682. time request.
  683. CPressureIn inherits almost all of its functionality
  684. from the CMIDIRecorder Class.
  685. CPressureIn receives MIDI Channel Pressure events through
  686. the RecordMIDI() command, which stores the
  687. time and value of the event.
  688. CPressureIn is called by CVoiceLFO to get the
  689. current values for the channel pressure to set the amount
  690. of LFO modulation for pitch.
  691. */
  692. class CPressureIn : public CMIDIRecorder
  693. {
  694. public:
  695. DWORD GetPressure(STIME stTime); // Gets the current channel pressure value.
  696. };
  697. //>>>> comment
  698. class CReverbIn : public CMIDIRecorder
  699. {
  700. public:
  701. CReverbIn();
  702. DWORD GetVolume(STIME stTime); // Gets the current reverb attenuation.
  703. };
  704. //>>>> comment
  705. class CChorusIn : public CMIDIRecorder
  706. {
  707. public:
  708. DWORD GetVolume(STIME stTime); // Gets the current chorus attenuation.
  709. };
  710. //>>>> comment
  711. class CCutOffFreqIn : public CMIDIRecorder
  712. {
  713. public:
  714. CCutOffFreqIn();
  715. DWORD GetFrequency(STIME stTime); // Gets the current pan.
  716. };
  717. class CWaveEvent {
  718. public:
  719. CWaveEvent() :
  720. m_stTime(0),
  721. m_bPart(0),
  722. m_dwVoiceId(0),
  723. m_vrVolume(0),
  724. m_prPitch(0),
  725. m_pWaveArt(NULL)
  726. {}
  727. public:
  728. STIME m_stTime;
  729. BYTE m_bPart;
  730. DWORD m_dwVoiceId;
  731. VREL m_vrVolume;
  732. PREL m_prPitch;
  733. SAMPLE_TIME m_stVoiceStart;
  734. SAMPLE_TIME m_stLoopStart;
  735. SAMPLE_TIME m_stLoopEnd;
  736. CWaveArt* m_pWaveArt;
  737. };
  738. class CWaveData : public CListItem
  739. {
  740. public:
  741. CWaveData();
  742. CWaveData * GetNext() {return (CWaveData *)CListItem::GetNext();};
  743. STIME m_stTime; // Time this event was recorded.
  744. CWaveEvent m_WaveEventData; // Data stored in event.
  745. };
  746. class CWaveDataList : public CList
  747. {
  748. public:
  749. CWaveData *GetHead() {return (CWaveData *)CList::GetHead();};
  750. CWaveData *RemoveHead() {return (CWaveData *)CList::RemoveHead();};
  751. };
  752. class CWaveIn
  753. {
  754. public:
  755. CWaveIn();
  756. ~CWaveIn(); // Be sure to clear local list.
  757. // BOOL FlushWave(STIME stTime); // Clear after time stamp.
  758. BOOL ClearWave(STIME stTime); // Clear up to time stamp.
  759. BOOL RemoveWave(DWORD dwID); // Remove wave with dwID.
  760. BOOL RemoveWaveByStopTime(DWORD dwID, STIME stStopTime);
  761. BOOL RecordWave(STIME stTime, CWaveEvent *pWaveData);
  762. BOOL GetWave(STIME stTime, CWaveEvent *pWave);
  763. private:
  764. static DWORD m_sUsageCount; // Keeps track of how many instances so free list can be released.
  765. public:
  766. static CWaveDataList m_sFreeList; // Global free list of events.
  767. protected:
  768. CWaveDataList m_EventList; // This recorder's list.
  769. STIME m_stCurrentTime; // Time for current value.
  770. CWaveEvent m_lCurrentData; // Current value.
  771. };
  772. /* The CVoiceLFO class is used to track the behavior
  773. of an LFO within a voice. The LFO is hard wired to
  774. output both volume and pitch values, through separate
  775. calls to GetVolume and GetPitch.
  776. It also manages mixing Mod Wheel control of pitch and
  777. volume LFO output. It tracks the scaling of Mod Wheel
  778. for each of these in m_nMWVolumeScale and m_nMWPitchScale.
  779. It calls the Mod Wheel module to get the current values
  780. if the respective scalings are greater than 0.
  781. All of the preset values for the LFO are carried in
  782. the m_CSource field, which is a replica of the file
  783. CSourceLFO structure. This is initialized with the
  784. StartVoice call.
  785. */
  786. class CVoiceLFO
  787. {
  788. public:
  789. CVoiceLFO();
  790. static void Init(); // Set up sine table.
  791. STIME StartVoice(CSourceLFO *pSource,
  792. STIME stStartTime,CModWheelIn * pModWheelIn, CPressureIn * pPressureIn);
  793. VREL GetVolume(STIME stTime, STIME *pstTime); // Returns volume cents.
  794. PREL GetPitch(STIME stTime, STIME *pstTime); // Returns pitch cents.
  795. /* DirectX8 Methods */
  796. void Enable(BOOL bEnable) {m_bEnable = bEnable;};
  797. PREL GetCutoff(STIME stTime); // Return filter cutoff
  798. private:
  799. long GetLevel(STIME stTime, STIME *pstTime);
  800. CSourceLFO m_Source; // All of the preset information.
  801. STIME m_stStartTime; // Time the voice started playing.
  802. CModWheelIn *m_pModWheelIn; // Pointer to Mod Wheel for this channel.
  803. STIME m_stRepeatTime; // Repeat time for LFO.
  804. static short m_snSineTable[256]; // Sine lookup table.
  805. /* DirectX8 Memmebers */
  806. CPressureIn *m_pPressureIn; // Pointer to Channel Pressure for this channel.
  807. BOOL m_bEnable;
  808. };
  809. /* The CVoiceEG class is used to track the behavior of
  810. an Envelope Generator within a voice. There are two
  811. EG's, one for pitch and one for volume. However, they
  812. behave identically.
  813. All of the preset values for the EG are carried in
  814. the m_Source field, which is a replica of the file
  815. CSourceEG structure. This is initialized with the
  816. StartVoice call.
  817. */
  818. class CVoiceEG
  819. {
  820. public:
  821. static void Init(); // Set up linear attack table.
  822. CVoiceEG();
  823. STIME StartVoice(CSourceEG *pSource, STIME stStartTime,
  824. WORD nKey, WORD nVelocity, STIME stMinAttack);
  825. void StopVoice(STIME stTime);
  826. void QuickStopVoice(STIME stTime, DWORD dwSampleRate);
  827. VREL GetVolume(STIME stTime, STIME *pstTime); // Returns volume cents.
  828. PREL GetPitch(STIME stTime, STIME *pstTime); // Returns pitch cents.
  829. BOOL InAttack(STIME stTime); // is voice still in attack?
  830. BOOL InRelease(STIME stTime); // is voice in release?
  831. /* DirectX8 Methods */
  832. void Enable(BOOL bEnable) {m_bEnable = bEnable;};
  833. PREL GetCutoff(STIME stTime); // Return filter cutoff
  834. private:
  835. long GetLevel(STIME stTime, STIME *pstTime, BOOL fVolume);
  836. CSourceEG m_Source; // Preset values for envelope, copied from file.
  837. STIME m_stStartTime; // Time note turned on
  838. STIME m_stStopTime; // Time note turned off
  839. static short m_snAttackTable[201];
  840. /* DirectX8 Memmebers */
  841. BOOL m_bEnable;
  842. };
  843. //>>>>>>>>>>> comment
  844. class CVoiceFilter
  845. {
  846. public:
  847. void StartVoice(CSourceFilter *pSource, CVoiceLFO *pLFO, CVoiceEG *pEG, WORD nKey, WORD nVelocity);
  848. void GetCoeff(STIME stTime, PREL prFreqIn, COEFF &cfK, COEFF &cfB1, COEFF &cfB2);
  849. BOOL IsFiltered();
  850. public:
  851. CSourceFilter m_Source;
  852. CVoiceLFO *m_pLFO;
  853. CVoiceEG *m_pEG;
  854. CPitchBendIn *m_pPitchBend;
  855. PREL m_prVelScale;
  856. PREL m_prKeyScale;
  857. static COEFF m_aK[FILTER_PARMS_DIM_Q][FILTER_PARMS_DIM_FC];
  858. static COEFF m_aB1[FILTER_PARMS_DIM_Q][FILTER_PARMS_DIM_FC];
  859. static COEFF m_aB2[FILTER_PARMS_DIM_Q][FILTER_PARMS_DIM_FC];
  860. };
  861. /* The CDigitalAudio class is used to track the playback
  862. of a sample within a voice.
  863. It manages the loop points, the pointer to the sample.
  864. and the base pitch and base volume, which it initially sets
  865. when called via StartVoice().
  866. Pitch is stored in a fixed point format, where the leftmost
  867. 20 bits define the sample increment and the right 12 bits
  868. define the factional increment within the sample. This
  869. format is also used to track the position in the sample.
  870. Mix is a critical routine. It is called by the CVoice to blend
  871. the instrument into the data buffer. It is handed relative change
  872. values for pitch and volume (semitone cents and decibel
  873. cents.) These it converts into three linear values:
  874. Left volume, Right volume, and Pitch.
  875. It then compares these new values with the values that existed
  876. for the previous slice and divides by the number of samples to
  877. determine an incremental change at the sample rate.
  878. Then, in the critical mix loop, these are added to the
  879. volume and pitch indices to give a smooth linear slope to the
  880. change in volume and pitch.
  881. */
  882. #define MAX_SAMPLE 4095
  883. #define MIN_SAMPLE (-4096)
  884. #define MAXDB 0
  885. #define MINDB -100
  886. #define TEST_WRITE_SIZE 3000
  887. #define TEST_SOURCE_SIZE 44100
  888. class CSynth;
  889. class CDigitalAudio
  890. {
  891. public:
  892. CDigitalAudio();
  893. ~CDigitalAudio();
  894. void ClearVoice();
  895. STIME StartVoice(CSynth *pSynth,
  896. CSourceSample *pSample,
  897. PREL prBasePitch, long lKey);
  898. STIME StartWave(CSynth *pSynth,
  899. CWaveArt *pWaveArt,
  900. PREL prBasePitch,
  901. SAMPLE_TIME stVoiceStart,
  902. SAMPLE_TIME stLoopStart,
  903. SAMPLE_TIME stLoopEnd);
  904. BOOL Mix(short **ppBuffers,
  905. DWORD dwInterleaved,
  906. DWORD dwBufferCount,
  907. DWORD dwLength,
  908. VREL vrMaxVolumeDelta,
  909. VFRACT vrNewVolume[],
  910. VFRACT vrLastVolume[],
  911. PREL dwPitch,
  912. DWORD dwIsFiltered, COEFF cfK, COEFF cfB1, COEFF cfB2);
  913. inline void BreakLoop()
  914. { m_bOneShot = TRUE; }
  915. static void Init(); // Set up lookup tables.
  916. static PFRACT PRELToPFRACT(PREL prPitch); // Pitch cents to pitch.
  917. static VFRACT VRELToVFRACT(VREL vrVolume); // dB to absolute.
  918. SAMPLE_POSITION GetCurrentPos() {return m_ullSamplesSoFar;};
  919. //
  920. // Optimized Interleaved mixers
  921. //
  922. private:
  923. DWORD Mix8(short * pBuffer,
  924. DWORD dwLength,
  925. DWORD dwDeltaPeriod,
  926. VFRACT vfDeltaLVolume,
  927. VFRACT vfDeltaRVolume,
  928. VFRACT vfLastVolume[],
  929. PFRACT pfDeltaPitch,
  930. PFRACT pfSampleLength,
  931. PFRACT pfLoopLength);
  932. DWORD Mix16(short * pBuffer,
  933. DWORD dwLength,
  934. DWORD dwDeltaPeriod,
  935. VFRACT vfDeltaLVolume,
  936. VFRACT vfDeltaRVolume,
  937. VFRACT vfLastVolume[],
  938. PFRACT pfDeltaPitch,
  939. PFRACT pfSampleLength,
  940. PFRACT pfLoopLength);
  941. DWORD MixMono8(short * pBuffer,
  942. DWORD dwLength,
  943. DWORD dwDeltaPeriod,
  944. VFRACT vfDeltaVolume,
  945. VFRACT vfLastVolume[],
  946. PFRACT pfDeltaPitch,
  947. PFRACT pfSampleLength,
  948. PFRACT pfLoopLength);
  949. DWORD MixMono16(short * pBuffer,
  950. DWORD dwLength,
  951. DWORD dwDeltaPeriod,
  952. VFRACT vfDeltaVolume,
  953. VFRACT vfLastVolume[],
  954. PFRACT pfDeltaPitch,
  955. PFRACT pfSampleLength,
  956. PFRACT pfLoopLength);
  957. //
  958. // Optimized MMX Interleaved mixers
  959. //
  960. private:
  961. DWORD _cdecl Mix8X(short * pBuffer,
  962. DWORD dwLength,
  963. DWORD dwDeltaPeriod,
  964. VFRACT vfDeltaLVolume,
  965. VFRACT vfDeltaRVolume,
  966. VFRACT vfLastVolume[],
  967. PFRACT pfDeltaPitch,
  968. PFRACT pfSampleLength,
  969. PFRACT pfLoopLength);
  970. DWORD _cdecl Mix16X(short * pBuffer,
  971. DWORD dwLength,
  972. DWORD dwDeltaPeriod,
  973. VFRACT vfDeltaLVolume,
  974. VFRACT vfDeltaRVolume,
  975. VFRACT vfLastVolume[],
  976. PFRACT pfDeltaPitch,
  977. PFRACT pfSampleLength,
  978. PFRACT pfLoopLength);
  979. DWORD MixMono16X(short * pBuffer,
  980. DWORD dwLength,
  981. DWORD dwDeltaPeriod,
  982. VFRACT vfDeltaVolume,
  983. VFRACT vfLastVolume[],
  984. PFRACT pfDeltaPitch,
  985. PFRACT pfSampleLength,
  986. PFRACT pfLoopLength);
  987. DWORD MixMono8X(short * pBuffer,
  988. DWORD dwLength,
  989. DWORD dwDeltaPeriod,
  990. VFRACT vfDeltaVolume,
  991. VFRACT vfLastVolume[],
  992. PFRACT pfDeltaPitch,
  993. PFRACT pfSampleLength,
  994. PFRACT pfLoopLength);
  995. //
  996. // Optimize Multi Buffer versions of the mixer
  997. //
  998. private:
  999. DWORD MixMulti8(short *ppBuffer[],
  1000. DWORD dwBufferCount,
  1001. DWORD dwLength,
  1002. DWORD dwDeltaPeriod,
  1003. VFRACT vfDeltaVolume[],
  1004. VFRACT vfLastVolume[],
  1005. PFRACT pfDeltaPitch,
  1006. PFRACT pfSampleLength,
  1007. PFRACT pfLoopLength);
  1008. DWORD MixMulti8Filter(short *ppBuffer[],
  1009. DWORD dwBufferCount,
  1010. DWORD dwLength,
  1011. DWORD dwDeltaPeriod,
  1012. VFRACT vfDeltaVolume[],
  1013. VFRACT vfLastVolume[],
  1014. PFRACT pfDeltaPitch,
  1015. PFRACT pfSampleLength,
  1016. PFRACT pfLoopLength,
  1017. COEFF cfdK,
  1018. COEFF cfdB1,
  1019. COEFF cfdB2);
  1020. DWORD MixMulti16(short *ppBuffer[],
  1021. DWORD dwBufferCount,
  1022. DWORD dwLength,
  1023. DWORD dwDeltaPeriod,
  1024. VFRACT vfDeltaVolume[],
  1025. VFRACT vfLastVolume[],
  1026. PFRACT pfDeltaPitch,
  1027. PFRACT pfSampleLength,
  1028. PFRACT pfLoopLength);
  1029. DWORD MixMulti16Filter(short *ppBuffer[],
  1030. DWORD dwBufferCount,
  1031. DWORD dwLength,
  1032. DWORD dwDeltaPeriod,
  1033. VFRACT vfDeltaVolume[],
  1034. VFRACT vfLastVolume[],
  1035. PFRACT pfDeltaPitch,
  1036. PFRACT pfSampleLength,
  1037. PFRACT pfLoopLength,
  1038. COEFF cfdK,
  1039. COEFF cfdB1,
  1040. COEFF cfdB2);
  1041. DWORD Mix8Filter(short * pBuffer,
  1042. DWORD dwLength,
  1043. DWORD dwDeltaPeriod,
  1044. VFRACT vfDeltaLVolume,
  1045. VFRACT vfDeltaRVolume,
  1046. VFRACT vfLastVolume[],
  1047. PFRACT pfDeltaPitch,
  1048. PFRACT pfSampleLength,
  1049. PFRACT pfLoopLength,
  1050. COEFF cfdK,
  1051. COEFF cfdB1,
  1052. COEFF cfdB2);
  1053. DWORD Mix16Filter(short * pBuffer,
  1054. DWORD dwLength,
  1055. DWORD dwDeltaPeriod,
  1056. VFRACT vfDeltaLVolume,
  1057. VFRACT vfDeltaRVolume,
  1058. VFRACT vfLastVolume[],
  1059. PFRACT pfDeltaPitch,
  1060. PFRACT pfSampleLength,
  1061. PFRACT pfLoopLength,
  1062. COEFF cfdK,
  1063. COEFF cfdB1,
  1064. COEFF cfdB2);
  1065. private:
  1066. void BeforeBigSampleMix();
  1067. void AfterBigSampleMix();
  1068. private:
  1069. CSourceSample m_Source; // Preset values for sample.
  1070. CSynth * m_pSynth; // For access to sample rate, etc.
  1071. static PFRACT m_spfCents[201]; // Pitch increment lookup.
  1072. static PFRACT m_spfSemiTones[97]; // Four octaves up and down.
  1073. static VFRACT m_svfDbToVolume[(MAXDB - MINDB) * 10 + 1]; // dB conversion table.
  1074. static BOOL m_sfMMXEnabled;
  1075. private:
  1076. short * m_pnWave; // Private pointer to wave.
  1077. PFRACT m_pfBasePitch; // Overall pitch.
  1078. PFRACT m_pfLastPitch; // The last pitch value.
  1079. PREL m_prLastPitch; // Same for pitch, in PREL.
  1080. PFRACT m_pfLastSample; // The last sample position.
  1081. PFRACT m_pfLoopStart; // Start of loop.
  1082. PFRACT m_pfLoopEnd; // End of loop.
  1083. PFRACT m_pfSampleLength; // Length of sample buffer.
  1084. BOOL m_fElGrande; // Indicates larger than 1m wave.
  1085. ULONGLONG m_ullLastSample; // Used to track > 1m wave.
  1086. ULONGLONG m_ullLoopStart; // Used to track > 1m wave.
  1087. ULONGLONG m_ullLoopEnd; // Used to track > 1m wave.
  1088. ULONGLONG m_ullSampleLength; // Used to track > 1m wave.
  1089. DWORD m_dwAddressUpper; // Temp storage for upper bits of address.
  1090. BOOL m_bOneShot; // Is the source region we're mixing a one-shot?
  1091. /* DLS2 filter members */
  1092. COEFF m_cfLastK; // Held filter coefficients
  1093. COEFF m_cfLastB1;
  1094. COEFF m_cfLastB2;
  1095. long m_lPrevSample; // Last two samples, post-filter
  1096. long m_lPrevPrevSample;
  1097. /* DirectX8 members */
  1098. CWaveBuffer* m_pCurrentBuffer;
  1099. CWaveArt* m_pWaveArt;
  1100. ULONGLONG m_ullSamplesSoFar;
  1101. };
  1102. /* The CVoice class pulls together everything needed to perform
  1103. one voice. It has the envelopes, lfo, and sample embedded
  1104. within it.
  1105. StartVoice() initializes a voice structure for playback. The
  1106. CSourceRegion structure carries the region and sample as well
  1107. as a pointer to the articulation, which is used to set up
  1108. the various articulation modules. It also carries pointers to
  1109. all the MIDI modulation inputs and the values for the note key
  1110. and channel which are used by the parent ControlLogic object
  1111. to match incoming note off events with the right voice.
  1112. */
  1113. class CVoice : public CListItem
  1114. {
  1115. public:
  1116. CVoice();
  1117. CVoice * GetNext() {return (CVoice *)CListItem::GetNext();};
  1118. BOOL StartVoice(CSynth *pControl,
  1119. CSourceRegion *pRegion, STIME stStartTime,
  1120. CModWheelIn * pModWheelIn,
  1121. CPitchBendIn * pPitchBendIn,
  1122. CExpressionIn * pExpressionIn,
  1123. CVolumeIn * pVolumeIn,
  1124. CPanIn * pPanIn,
  1125. CPressureIn * pPressureIn,
  1126. CReverbIn * pReverbSend,
  1127. CChorusIn * pChorusSend,
  1128. CCutOffFreqIn * PCCutOffFreqIn,
  1129. CBusIds * pBusIds,
  1130. WORD nKey,WORD nVelocity,
  1131. VREL vrVolume, // Added for GS
  1132. PREL prPitch); // Added for GS
  1133. BOOL StartWave(CSynth *pSynth,
  1134. CWaveArt *pWaveArt,
  1135. DWORD dwVoiceId,
  1136. STIME stStartTime,
  1137. CPitchBendIn * pPitchBendIn,
  1138. CExpressionIn * pExpressionIn,
  1139. CVolumeIn * pVolumeIn,
  1140. CPanIn * pPanIn,
  1141. CReverbIn * pReverbSend,
  1142. CChorusIn * pChorusSend,
  1143. CCutOffFreqIn * pCCutOffFreqIn,
  1144. CBusIds * pBusIds,
  1145. VREL vrVolume,
  1146. PREL prPitch,
  1147. SAMPLE_TIME stVoiceStart,
  1148. SAMPLE_TIME stLoopStart,
  1149. SAMPLE_TIME stLoopEnd
  1150. );
  1151. static void Init(); // Initialize LFO, Digital Audio.
  1152. void StopVoice(STIME stTime);// Called on note off event.
  1153. void QuickStopVoice(STIME stTime);// Called to get quick release.
  1154. void SpeedRelease(); // Force an already off envelope to release quickly.
  1155. void ClearVoice(); // Release use of sample.
  1156. void GetNewPitch(STIME stTime, PREL& prPitch);// Return current pitch value
  1157. void GetNewVolume(STIME stTime, VREL& vrVolume, VREL& vrVolumeL, VREL& vrVolumeR, VREL& vrVolumeReverb, VREL& vrVolumeChorus);
  1158. void GetNewCoeff(STIME stTime, PREL& prCutOff, COEFF& cfK, COEFF& cfB1, COEFF& cfB2);
  1159. DWORD Mix(short **ppvBuffer, DWORD dwBufferFlags, DWORD dwLength, STIME stStart,STIME stEnd);
  1160. SAMPLE_POSITION GetCurrentPos();
  1161. private:
  1162. static VREL m_svrPanToVREL[128];// Converts Pan to db.
  1163. CVoiceLFO m_LFO; // LFO.
  1164. CVoiceEG m_PitchEG; // Pitch Envelope.
  1165. CVoiceEG m_VolumeEG; // Volume Envelope.
  1166. CDigitalAudio m_DigitalAudio; // The Digital Audio Engine structure.
  1167. CPitchBendIn * m_pPitchBendIn; // Pitch bend source.
  1168. CExpressionIn * m_pExpressionIn;// Expression source.
  1169. CVolumeIn * m_pVolumeIn; // Volume source, if allowed to vary
  1170. CPanIn * m_pPanIn; // Pan source, if allowed to vary
  1171. CReverbIn * m_pReverbSend; //>>>> comment
  1172. CChorusIn * m_pChorusSend; //>>>> comment
  1173. CCutOffFreqIn * m_CCutOffFreqIn;//>>>> comment
  1174. CSynth * m_pSynth; // To access sample rate, etc.
  1175. STIME m_stMixTime; // Next time we need a mix.
  1176. STIME m_stLastMix; // Last sample position mixed.
  1177. long m_lDefaultPan; // Default pan
  1178. PREL m_prLastCutOff; // Last cut off value.
  1179. public:
  1180. DWORD m_dwNoteID; // Unique id to keep all voices that represent layers of one note connected.
  1181. STIME m_stStartTime; // Time the sound starts.
  1182. STIME m_stStopTime; // Time the sound stops.
  1183. STIME m_stWaveStopTime; // Stop time set by direct call to stop the wave voice.
  1184. BOOL m_fInUse; // This is currently in use.
  1185. BOOL m_fNoteOn; // Note is considered on.
  1186. BOOL m_fTag; // Used to track note stealing.
  1187. VREL m_vrVolume; // Volume, used for voice stealing...
  1188. BOOL m_fSustainOn; // Sus pedal kept note on after off event.
  1189. WORD m_nPart; // Part that is playing this (channel).
  1190. WORD m_nKey; // Note played.
  1191. BOOL m_fAllowOverlap; // Allow overlapped note.
  1192. DWORD m_dwGroup; // Group this voice is playing now
  1193. DWORD m_dwProgram; // Bank and Patch choice.
  1194. DWORD m_dwPriority; // Priority.
  1195. CControlLogic * m_pControl; // Which control group is playing voice.
  1196. DWORD m_dwVoiceId; // Used to identify a playing wave
  1197. CSourceRegion *m_pRegion; // Used to determin which region a voice is playing out of
  1198. CVoiceFilter m_Filter; // Low pass filter
  1199. CVoiceLFO m_LFO2; // Vibrato
  1200. CBusIds m_BusIds; // Bus Id's to playe on this voice
  1201. DWORD m_dwLoopType; // Loop type
  1202. BOOL m_fIgnorePan; // If we're part of a multichannel wave/sample
  1203. VREL m_vrLastVolume[MAX_DAUD_CHAN];
  1204. VREL m_vrBaseVolume[MAX_DAUD_CHAN];
  1205. VFRACT m_vfLastVolume[MAX_DAUD_CHAN];
  1206. };
  1207. class CVoiceList : public CList
  1208. {
  1209. public:
  1210. CVoice * GetHead() {return (CVoice *)CList::GetHead();};
  1211. CVoice * RemoveHead() {return (CVoice *)CList::RemoveHead();};
  1212. CVoice * GetItem(LONG lIndex) {return (CVoice *) CList::GetItem(lIndex);};
  1213. };
  1214. /* Finally, ControlLogic is the big Kahuna that manages
  1215. the whole system. It parses incoming MIDI events
  1216. by channel and event type. And, it manages the mixing
  1217. of voices into the buffer.
  1218. MIDI Input:
  1219. The most important events are the note on and
  1220. off events. When a note on event comes in,
  1221. ControlLogic searches for an available voice.
  1222. ControlLogic matches the channel and finds the
  1223. instrument on that channel. It then call the instrument's
  1224. ScanForRegion() command which finds the region
  1225. that matches the note. At this point, it can copy
  1226. the region and associated articulation into the
  1227. voice, using the StartVoice command.
  1228. When it receives the sustain pedal command,
  1229. it artificially sets all notes on the channel on
  1230. until a sustain off arrives. To keep track of notes
  1231. that have been shut off while the sustain was on
  1232. it uses an array of 128 shorts, with each bit position
  1233. representing a channel. When the sustain releases,
  1234. it scans through the array and creates a note off for
  1235. each bit that was set.
  1236. It also receives program change events to set the
  1237. instrument choice for the channel. When such
  1238. a command comes in, it consults the softsynth.ini file
  1239. and loads an instrument with the file name described
  1240. in the ini file.
  1241. Additional continuous controller events are managed
  1242. by the CModWheelIn, CPitchBendIn, etc., MIDI input recording
  1243. modules.
  1244. Mixing:
  1245. Control Logic is also called to mix the instruments into
  1246. a buffer at regular intervals. The buffer is provided by the
  1247. calling sound driver (initially, AudioMan.)
  1248. Each voice is called to mix its sample into the buffer.
  1249. */
  1250. typedef struct PerfStats
  1251. {
  1252. DWORD dwTotalTime;
  1253. DWORD dwTotalSamples;
  1254. DWORD dwNotesLost;
  1255. DWORD dwVoices;
  1256. DWORD dwCPU;
  1257. DWORD dwMaxAmplitude;
  1258. } PerfStats;
  1259. #define MIX_BUFFER_LEN 500 // Set the sample buffer size to 500 mils
  1260. #define MAX_NUM_VOICES 32
  1261. #define NUM_EXTRA_VOICES 8 // Extra voices for when we overload.
  1262. #define NUM_DEFAULT_BUSES 4
  1263. class CControlLogic
  1264. {
  1265. public:
  1266. CControlLogic();
  1267. ~CControlLogic();
  1268. HRESULT Init(CInstManager *pInstruments, CSynth *pSynth);
  1269. void ClearAll();
  1270. void Flush(STIME stTime); // Clears all events after time.
  1271. BOOL RecordMIDI(STIME stTime,BYTE bStatus, BYTE bData1, BYTE bData2);
  1272. HRESULT RecordSysEx(DWORD dwSysExLength,BYTE *pSysExData, STIME stTime);
  1273. CSynth * m_pSynth;
  1274. void QueueNotes(STIME stStartTime, STIME stEndTime);
  1275. void ClearMIDI(STIME stEndTime);
  1276. void SetGainAdjust(VREL vrGainAdjust);
  1277. HRESULT SetChannelPriority(DWORD dwChannel,DWORD dwPriority);
  1278. HRESULT GetChannelPriority(DWORD dwChannel,LPDWORD pdwPriority);
  1279. /* DirectX8 methods */
  1280. void QueueWaves(STIME stEndTime);
  1281. void FlushWaveByStopTime(DWORD dwID, STIME stStopTime);
  1282. BOOL RecordWaveEvent(STIME stTime, BYTE bChannel, DWORD dwVoiceId, VREL prVolume, PREL prPitch, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd, CWaveArt* pWaveArt);
  1283. HRESULT AssignChannelToBuses(DWORD dwChannel, LPDWORD pdwBusIds, DWORD dwBusCount);
  1284. private:
  1285. void GMReset();
  1286. CInstManager * m_pInstruments;
  1287. CNoteIn m_Notes; // All Note ons and offs.
  1288. CModWheelIn m_ModWheel[16]; // Sixteen channels of Mod Wheel.
  1289. CPitchBendIn m_PitchBend[16]; // Sixteen channels of Pitch Bend.
  1290. CVolumeIn m_Volume[16]; // Sixteen channels of Volume.
  1291. CExpressionIn m_Expression[16]; // Sixteen channels of Expression.
  1292. CPanIn m_Pan[16]; // Sixteen channels of Pan.
  1293. CReverbIn m_ReverbSends[16]; //>>>> comment
  1294. CChorusIn m_ChorusSends[16]; //>>>> comment
  1295. CCutOffFreqIn m_CutOffFreqCC[16]; //>>>> comment
  1296. BOOL m_fSustain[16]; // Sustain on / off.
  1297. short m_nCurrentRPN[16]; // RPN number.
  1298. BYTE m_bBankH[16]; // Bank selects for instrument.
  1299. BYTE m_bBankL[16];
  1300. DWORD m_dwProgram[16]; // Instrument choice.
  1301. BOOL m_fEmpty; // Indicates empty lists, no need to flush.
  1302. VREL m_vrGainAdjust; // Final stage gain adjust
  1303. DWORD m_dwPriority[16]; // Priorities for each channel.
  1304. BOOL m_fXGActive; // Is XG Active?
  1305. BOOL m_fGSActive; // Is GS enabled?
  1306. WORD m_nData[16]; // Used to track RPN reading.
  1307. VREL m_vrMasterVolume; // Master Volume.
  1308. PREL m_prFineTune[16]; // Fine tune for each channel.
  1309. PREL m_prScaleTune[16][12]; // Alternate scale for each channel.
  1310. PREL m_prCoarseTune[16]; // Coarse tune.
  1311. BYTE m_bPartToChannel[16]; // Channel to Part converter.
  1312. BYTE m_bDrums[16]; // Melodic or which drum?
  1313. BOOL m_fMono[16]; // Mono mode?
  1314. public:
  1315. // This is static to protect the CMIDIRecorder free list, which is also static.
  1316. //
  1317. static CRITICAL_SECTION s_CriticalSection; // Critical section to manage access.
  1318. static BOOL s_fCSInitialized;
  1319. static BOOL InitCriticalSection();
  1320. static void KillCriticalSection();
  1321. /* DirectX8 members */
  1322. private:
  1323. CWaveIn m_Waves; // All waves scheduled to be played
  1324. CPressureIn m_Pressure[16]; // Sixteen channels of Channel Pressure.
  1325. CBusIds m_BusIds[16]; // Bus Id's for each channel
  1326. };
  1327. #endif // __SYNTH_H__