• R/O
  • SSH
  • HTTPS

cadencii: コミット


コミットメタ情報

リビジョン9 (tree)
日時2009-03-16 23:03:09
作者kbinani

ログメッセージ

(メッセージはありません)

変更サマリ

差分

--- trunk/Cadencii/VSTiProxy.cs (nonexistent)
+++ trunk/Cadencii/VSTiProxy.cs (revision 9)
@@ -0,0 +1,1182 @@
1+/*
2+ * VSTiProxy.cs
3+ * Copyright (c) 2008-2009 kbinani
4+ *
5+ * This file is part of Boare.Cadencii.
6+ *
7+ * Boare.Cadencii is free software; you can redistribute it and/or
8+ * modify it under the terms of the BSD License.
9+ *
10+ * Boare.Cadencii is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13+ */
14+#define TEST_NEW_VSTIPROXY
15+#define TEST
16+using System;
17+using System.IO;
18+using System.Runtime.InteropServices;
19+using System.Collections.Generic;
20+using System.Threading;
21+using System.ComponentModel;
22+using System.Security;
23+using System.Windows.Forms;
24+
25+using Boare.Lib.Vsq;
26+using Boare.Lib.Media;
27+
28+namespace Boare.Cadencii {
29+
30+ public enum VSTiProxyTrackType {
31+ TempoTrack,
32+ MainTrack,
33+ }
34+
35+ [StructLayout( LayoutKind.Sequential, Pack = 1 )]
36+ struct VstEvent : IComparable<VstEvent> {
37+ public Int32 type;
38+ public Int32 byteSize;
39+ public Int32 deltaFrames;
40+ public Int32 flags;
41+ byte data0;
42+ byte data1;
43+ byte data2;
44+ byte data3;
45+ byte data4;
46+ byte data5;
47+ byte data6;
48+ byte data7;
49+ byte data8;
50+ byte data9;
51+ byte data10;
52+ byte data11;
53+ byte data12;
54+ byte data13;
55+ byte data14;
56+ byte data15;
57+
58+ public int CompareTo( VstEvent item ) {
59+ return deltaFrames - item.deltaFrames;
60+ }
61+
62+ public byte this[int index] {
63+ get {
64+ switch ( index ) {
65+ case 0:
66+ return data0;
67+ case 1:
68+ return data1;
69+ case 2:
70+ return data2;
71+ case 3:
72+ return data3;
73+ case 4:
74+ return data4;
75+ case 5:
76+ return data5;
77+ case 6:
78+ return data6;
79+ case 7:
80+ return data7;
81+ case 8:
82+ return data8;
83+ case 9:
84+ return data9;
85+ case 10:
86+ return data10;
87+ case 11:
88+ return data11;
89+ case 12:
90+ return data12;
91+ case 13:
92+ return data13;
93+ case 14:
94+ return data14;
95+ case 15:
96+ return data15;
97+ default:
98+ throw new ArgumentOutOfRangeException();
99+ }
100+ }
101+ set {
102+ switch ( index ) {
103+ case 0:
104+ data0 = value;
105+ break;
106+ case 1:
107+ data1 = value;
108+ break;
109+ case 2:
110+ data2 = value;
111+ break;
112+ case 3:
113+ data3 = value;
114+ break;
115+ case 4:
116+ data4 = value;
117+ break;
118+ case 5:
119+ data5 = value;
120+ break;
121+ case 6:
122+ data6 = value;
123+ break;
124+ case 7:
125+ data7 = value;
126+ break;
127+ case 8:
128+ data8 = value;
129+ break;
130+ case 9:
131+ data9 = value;
132+ break;
133+ case 10:
134+ data10 = value;
135+ break;
136+ case 11:
137+ data11 = value;
138+ break;
139+ case 12:
140+ data12 = value;
141+ break;
142+ case 13:
143+ data13 = value;
144+ break;
145+ case 14:
146+ data14 = value;
147+ break;
148+ case 15:
149+ data15 = value;
150+ break;
151+ default:
152+ throw new ArgumentOutOfRangeException();
153+ }
154+ }
155+ }
156+ }
157+
158+ unsafe struct MIDI_EVENT {
159+ public uint clock;
160+ public MIDI_EVENT* pNext;
161+ public uint dwDataSize;
162+ public byte dwOffset;
163+ public byte* pMidiEvent;
164+ }
165+
166+ public static class VSTiProxy {
167+ private const int _SAMPLE_RATE = 44100;
168+ private const int _BLOCK_SIZE = 44100;
169+
170+ private static string s_dll_path = "";
171+ public static string CurrentUser = "";
172+ private static bool s_loaded = false;
173+ private static Wave s_wave;
174+ //private static WaveWriter s_wave;
175+ private static bool s_rendering = false;
176+ private static int s_trim_remain = 0;
177+ private static object s_locker;
178+ private static double s_amplify_left = 1.0;
179+ private static double s_amplify_right = 1.0;
180+
181+ static VSTiProxy() {
182+ try {
183+ s_locker = new object();
184+ s_dll_path = VsqUtil.VstiDllPath;
185+#if DEBUG
186+ Common.DebugWriteLine( "VSTiProxy+Init()" );
187+ Common.DebugWriteLine( " s_dll_path=" + s_dll_path );
188+#endif
189+ char[] str = s_dll_path.ToCharArray();
190+ if ( s_dll_path != "" ) {
191+ s_loaded = vstidrv.Init( str, _BLOCK_SIZE, _SAMPLE_RATE );
192+ } else {
193+ s_loaded = false;
194+ }
195+#if TEST
196+ bocoree.debug.PushLog( "VSTiProxy..cctor()" );
197+ bocoree.debug.PushLog( " s_dll_path=" + s_dll_path );
198+ bocoree.debug.PushLog( " s_loaded=" + s_loaded );
199+#endif
200+ } catch ( Exception ex ) {
201+#if TEST
202+ bocoree.debug.PushLog( " ex=" + ex );
203+#endif
204+ }
205+ }
206+
207+ public static unsafe void RenderToWave( NrpnData[] nrpn, TempoTableEntry[] tempo, int clEos, string file, double amplify_left, double amplify_right ) {
208+#if TEST
209+ Console.WriteLine( "VSTiProxy.RenderToWave( NRPN[], TempoTableEntry[], int, string )" );
210+ bocoree.debug.PushLog( "VSTiPRoxy+RenderToWave(NrpnData[], TempoTableEntry[], int, string)" );
211+#endif
212+ if ( !s_loaded ) {
213+ return;
214+ }
215+ int tempo_count = tempo.Length;
216+ float first_tempo = 125.0f;
217+ if ( tempo.Length > 0 ) {
218+ first_tempo = (float)(60e6 / (double)tempo[0].Tempo);
219+ }
220+ byte[] masterEventsSrc = new byte[tempo_count * 3];
221+ int[] masterClocksSrc = new int[tempo_count];
222+ int count = -3;
223+ for ( int i = 0; i < tempo.Length; i++ ) {
224+ count += 3;
225+ masterClocksSrc[i] = tempo[i].Clock;
226+ byte b0 = (byte)(tempo[i].Tempo >> 16);
227+ uint u0 = (uint)(tempo[i].Tempo - (b0 << 16));
228+ byte b1 = (byte)(u0 >> 8);
229+ byte b2 = (byte)(u0 - (u0 << 8));
230+#if DEBUG
231+ Console.WriteLine( " b0-b2=0x" + Convert.ToString( b0, 16 ) + ", 0x" + Convert.ToString( b1, 16 ) + ", 0x" + Convert.ToString( b2, 16 ) );
232+#endif
233+ masterEventsSrc[count] = b0;
234+ masterEventsSrc[count + 1] = b1;
235+ masterEventsSrc[count + 2] = b2;
236+ }
237+ fixed ( byte* masterEvents = &masterEventsSrc[0] )
238+ fixed ( int* masterClocks = &masterClocksSrc[0] ) {
239+ vstidrv.SendEvent( masterEvents, masterClocks, tempo_count, (int)VSTiProxyTrackType.TempoTrack );
240+ }
241+
242+ int numEvents = nrpn.Length + 1;
243+ byte[] bodyEventsSrc = new byte[numEvents * 3];
244+ int[] bodyClocksSrc = new int[numEvents];
245+ count = -3;
246+ int last_clock = 0;
247+#if DEBUG
248+ string test = Path.Combine( Path.GetDirectoryName( file ), Path.GetFileNameWithoutExtension( file ) + ".txt" );
249+ StreamWriter sw = new StreamWriter( test, false );
250+#endif
251+ for ( int i = 0; i < numEvents - 1; i++ ) {
252+ count += 3;
253+ bodyEventsSrc[count] = 0xb0;
254+ bodyEventsSrc[count + 1] = nrpn[i].Parameter;
255+ bodyEventsSrc[count + 2] = nrpn[i].Value;
256+ bodyClocksSrc[i] = nrpn[i].Clock;
257+ last_clock = nrpn[i].Clock;
258+#if DEBUG
259+ sw.WriteLine( nrpn[i].Clock + "\t0x" + Convert.ToString( nrpn[i].Parameter, 16 ) + "\t0x" + Convert.ToString( nrpn[i].Value, 16 ) );
260+#endif
261+ }
262+#if DEBUG
263+ sw.Close();
264+#endif
265+ count += 3;
266+ bodyEventsSrc[count] = 0xff;
267+ bodyEventsSrc[count + 1] = 0x2f;
268+ bodyEventsSrc[count + 2] = 0x00;
269+ bodyClocksSrc[numEvents - 1] = clEos;
270+ int index = tempo_count - 1;
271+ for ( int i = tempo_count - 1; i >= 0; i-- ) {
272+ if ( tempo[i].Clock < last_clock ) {
273+ index = i;
274+ break;
275+ }
276+ }
277+ int last_tempo = tempo[index].Tempo;
278+
279+ fixed ( byte* bodyEvents = &bodyEventsSrc[0] )
280+ fixed ( int* bodyClocks = &bodyClocksSrc[0] ) {
281+ vstidrv.SendEvent( bodyEvents, bodyClocks, numEvents, (int)VSTiProxyTrackType.MainTrack );
282+ }
283+
284+ s_rendering = true;
285+ s_wave = new Wave( WaveChannel.Stereo, 16, _SAMPLE_RATE, 0 );
286+ s_trim_remain = GetErrorSamples( first_tempo );
287+#if DEBUG
288+ bocoree.debug.PushLog( " first_tempo=" + first_tempo );
289+ bocoree.debug.PushLog( " s_trim_remain=" + s_trim_remain );
290+#endif
291+#if TEST_NEW_VSTIPROXY
292+ if ( s_trim_remain < 0 ) {
293+ double[] d = new double[-s_trim_remain];
294+ for ( int i = 0; i < -s_trim_remain; i++ ) {
295+ d[i] = 0.0;
296+ }
297+ s_wave.Append( d, d );
298+ s_trim_remain = 0;
299+ }
300+#endif
301+ s_amplify_left = amplify_left;
302+ s_amplify_right = amplify_right;
303+ vstidrv.WaveIncoming += VSTi3_WaveIncoming;
304+ vstidrv.RenderingFinished += VSTi3_RenderingFinished;
305+ vstidrv.StartRendering( clEos );
306+ while ( s_rendering ) {
307+ Application.DoEvents();
308+ }
309+ s_rendering = false;
310+ vstidrv.WaveIncoming -= VSTi3_WaveIncoming;
311+ vstidrv.RenderingFinished -= VSTi3_RenderingFinished;
312+ s_wave.Write( file );
313+ s_wave.Dispose();
314+ s_wave = null;
315+ }
316+
317+ static void VSTi3_RenderingFinished( object sender, EventArgs e ) {
318+ s_rendering = false;
319+ }
320+
321+ static void VSTi3_WaveIncoming( double[] L, double[] R ) {
322+#if TEST_NEW_VSTIPROXY
323+ lock ( s_locker ) {
324+ if ( s_trim_remain > 0 ) {
325+ if ( s_trim_remain >= L.Length ) {
326+ s_trim_remain -= L.Length;
327+ return;
328+ }
329+ int actual_append = L.Length - s_trim_remain;
330+ double[] dL = new double[actual_append];
331+ double[] dR = new double[actual_append];
332+ Array.Copy( L, L.Length - actual_append, dL, 0, actual_append );
333+ Array.Copy( R, L.Length - actual_append, dR, 0, actual_append );
334+ if ( s_amplify_left != 0.0 ) {
335+ for ( int i = 0; i < dL.Length; i++ ) {
336+ dL[i] = dL[i] * s_amplify_left;
337+ }
338+ }
339+ if ( s_amplify_right != 0.0 ) {
340+ for ( int i = 0; i < dR.Length; i++ ) {
341+ dR[i] = dR[i] * s_amplify_right;
342+ }
343+ }
344+ s_wave.Append( dL, dR );
345+ dL = null;
346+ dR = null;
347+ s_trim_remain = 0;
348+ } else {
349+#endif
350+ if ( s_amplify_left != 0.0 ) {
351+ for ( int i = 0; i < L.Length; i++ ) {
352+ L[i] = L[i] * s_amplify_left;
353+ }
354+ }
355+ if ( s_amplify_right != 0.0 ) {
356+ for ( int i = 0; i < R.Length; i++ ) {
357+ R[i] = R[i] * s_amplify_right;
358+ }
359+ }
360+ s_wave.Append( L, R );
361+#if TEST_NEW_VSTIPROXY
362+ }
363+ }
364+#endif
365+ }
366+
367+ public static double GetProgress() {
368+ if ( s_loaded ) {
369+ return vstidrv.GetProgress();
370+ } else {
371+ return 0.0;
372+ }
373+ }
374+
375+ public static void AbortRendering() {
376+ if ( s_rendering ) {
377+ s_rendering = false;
378+ vstidrv.AbortRendering();
379+ }
380+ }
381+
382+ /*public static string CurrentUser {
383+ get {
384+#if DEBUG
385+ Console.WriteLine( "VSTiProxy+get_CurrentUser" );
386+#endif
387+ return s_current_user;
388+ }
389+ set {
390+#if DEBUG
391+ Console.WriteLine( "VSTiPRoxy+set_CurrentUser" );
392+#endif
393+ s_current_user = value;
394+ }
395+ }*/
396+
397+ private static int GetErrorSamples( float tempo ) {
398+ const float a0 = -17317.563f;
399+ const float a1 = 86.7312112f;
400+ const float a2 = -0.237323499f;
401+ if ( tempo <= 240 ) {
402+ return 4666;
403+ } else {
404+ float x = tempo - 240;
405+ return (int)((a2 * x + a1) * x + a0);
406+ }
407+ }
408+ }
409+
410+ /// <summary>
411+ /// C++製dll,VSTi2.dllを使った,VSTiホストへのプラクシー
412+ /// </summary>
413+ static class VSTiProxy_ {
414+ private static bool s_loaded = false;
415+ private static string s_dll_path = "C:\\Program Files\\Steinberg\\VSTplugins\\VOCALOID2\\VOCALOID2.dll";
416+ private static int s_error_counter = 0;
417+ private static int s_sample_rate = 44100;
418+ private static string s_current_user = "";
419+
420+ const int NUM_ERR_THRESHOLD = 10;
421+ const int _BLOCK_SIZE = 44100;
422+ const int _SAMPLE_RATE = 44100;
423+ /* /// ファイル名を指定してプラグインを読み込む
424+ int __declspec(dllexport) LoadPluginA( char *name, int blockSize, int sampleRate );
425+ /// ファイル名を指定してプラグインを読み込む(ユニコード版)
426+ int __declspec(dllexport) LoadPluginW( WCHAR *name, int blockSize, int sampleRate );
427+ /// プラグインを開放する
428+ int __declspec(dllexport) FreePlugin();
429+ /// プラグインに送るmidiデータを指定する。
430+ int __declspec(dllexport) SendEvent( unsigned char *src, int *deltaFrames, int numEventsm, int targetTrack );
431+ /// 音符1個分のレンダリングを進める。続きのレンダリングはRenderContinueで行う。戻り値は、残りのフレーム数
432+ int __declspec(dllexport) RenderFirst( int *outL, int *outR, int sampleFrames );
433+ /// RenderFirstでレンダリング出来なかった残りの部分のレンダリングを行う。戻り値は、残りのフレーム数
434+ int __declspec(dllexport) RenderContinue( int *outL, int *outR, int sampleFrames );
435+ int __declspec(dllexport) RenderToWave( TCHAR *path );*/
436+
437+ [DllImport( "VSTi2.dll", CharSet = CharSet.Ansi, EntryPoint = "LoadPluginA" )]
438+ private static extern int LoadPluginA_( string name, int blockSize, int sampleRate );
439+
440+ [DllImport( "VSTi2.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadPluginW" )]
441+ private static extern int LoadPluginW_( string name, int blockSize, int sampleRate );
442+
443+ /*[System.Security.SuppressUnmanagedCodeSecurity]
444+ [DllImport( "VSTi2.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadPluginW", CallingConvention = CallingConvention.StdCall )]
445+ private static extern int UnsafeLoadPluginWStdCall( string name, int blockSize, int sampleRate );*/
446+
447+ [SuppressUnmanagedCodeSecurity]
448+ [DllImport( "VSTi2.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadPluginW", CallingConvention = CallingConvention.Cdecl )]
449+ private static extern int UnsafeLoadPluginWCdecl( string name, int blockSize, int sampleRate );
450+
451+ [DllImport( "VSTi2.dll", EntryPoint = "SendEvent" )]
452+ private static unsafe extern int SendEvent_( byte* src, int* deltaFrames, int numEvents, int targetTrack );
453+
454+ [DllImport( "VSTi2.dll", CharSet = CharSet.Unicode, EntryPoint = "RenderToWaveW" )]
455+ private static extern int RenderToWaveW_( string name, uint eof_clock );
456+
457+ [DllImport( "VSTi2.dll", EntryPoint = "FreePlugin" )]
458+ private static extern int FreePlugin_();
459+
460+ [DllImport( "VSTi2.dll", EntryPoint = "SetSampleRate" )]
461+ private static extern int SetSampleRate_( float sample_rate );
462+
463+ [DllImport( "VSTi2.dll", EntryPoint = "MainsChanged" )]
464+ private static extern int MainsChanged_( int status );
465+
466+ [DllImport( "VSTi2.dll", EntryPoint = "SetBlockSize" )]
467+ private static extern int SetBlockSize_( int block_size );
468+
469+ [DllImport( "VSTi2.dll", EntryPoint = "ProcessEvents" )]
470+ private static unsafe extern int ProcessEvents_( int numEvents, VstEvent* events );
471+
472+ [DllImport( "VSTi2.dll", EntryPoint = "ProcessReplacing" )]
473+ private static unsafe extern void ProcessReplacing_( float** out_buffer, int frames );
474+
475+ [DllImport( "VSTi2.dll", EntryPoint = "AbortRendering" )]
476+ private static extern void AbortRendering_();
477+
478+ [DllImport( "VSTi2.dll", EntryPoint = "GetProgress" )]
479+ private static extern double GetProgress_();
480+
481+ /// <summary>
482+ /// このクラスを使っているMainFormを特定するIDを取得、または設定します。""なら、どのFormMainのインスタンスもコイツを使ってない
483+ /// </summary>
484+ public static string CurrentUser {
485+ get {
486+ return s_current_user;
487+ }
488+ set {
489+ s_current_user = value;
490+ }
491+ }
492+
493+ public static bool ReloadPlugin() {
494+ if ( s_loaded ) {
495+ if ( FreePlugin() ) {
496+ s_loaded = false;
497+ } else {
498+ return false;
499+ }
500+ }
501+ return LoadPlugin( _BLOCK_SIZE, _SAMPLE_RATE );
502+ }
503+
504+ public static double GetProgress() {
505+ return GetProgress_();
506+ }
507+
508+ public static int SampleRate {
509+ get {
510+ return s_sample_rate;
511+ }
512+ set {
513+ s_sample_rate = value;
514+ }
515+ }
516+
517+ private static double totalMilliSec_from_timeCode( uint timeCode, TempoTableEntry[] tempo ) {
518+ const int _TIME_FORMAT = 480;
519+ const int DEF_TEMPO = 500000; // デフォルトのテンポ.
520+ double ret = 0.0;
521+ int index = -1;
522+ for ( int i = 0; i < tempo.Length; i++ ) {
523+ if ( timeCode <= tempo[i].Clock ) {
524+ break;
525+ }
526+ index = i;
527+ }
528+ if ( index >= 0 ) {
529+ ret = tempo[index].Time + (timeCode - tempo[index].Clock) * (double)tempo[index].Tempo / (1000.0 * _TIME_FORMAT);
530+ } else {
531+ ret = timeCode * (double)DEF_TEMPO / (1000.0 * _TIME_FORMAT);
532+ }
533+ return ret;
534+ }
535+
536+ public static unsafe int NEW_RenderToWave( NrpnData[] nrpn, TempoTableEntry[] tempo, int clEos, string file ) {
537+ if ( !s_loaded ) {
538+ s_loaded = LoadPlugin( 44100, 44100 );
539+ }
540+ /*WAVEFORMATEX wf;
541+ wf.nChannels = 2;
542+ wf.wFormatTag = WAVE_FORMAT_PCM;
543+ wf.wBitsPerSample = 16;
544+ wf.nBlockAlign = wf.nChannels*wf.wBitsPerSample/8;
545+ wf.nSamplesPerSec = g_sampleRate;// sampleFrames;
546+ wf.nAvgBytesPerSec = wf.nSamplesPerSec*wf.nBlockAlign;
547+
548+ // Create WAV
549+ HMMIO hmmio = mmioOpen( path, NULL, MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE );
550+ MMCKINFO mmckRiff, mmckData, mmckFmt;
551+ mmckRiff.fccType = mmioStringToFOURCC( TEXT("WAVE"), 0 );
552+ mmioCreateChunk( hmmio, &mmckRiff, MMIO_CREATERIFF );
553+ mmckFmt.ckid = mmioStringToFOURCC( TEXT("fmt "), 0 );
554+ mmioCreateChunk( hmmio, &mmckFmt, 0 );
555+ mmioWrite( hmmio, (char*)&wf, sizeof(WAVEFORMATEX) );
556+ mmioAscend( hmmio, &mmckFmt, 0 );
557+
558+ mmckData.ckid = mmioStringToFOURCC( TEXT("data"), 0 );
559+ mmioCreateChunk( hmmio, &mmckData, 0 );*/
560+
561+ //MIDI_EVENT* lpEvents = merge_events( g_ppTrackEvents[0], g_ppTrackEvents[1] );
562+ //MIDI_EVENT* current = lpEvents;
563+ List<VstEvent> proc = new List<VstEvent>();
564+ for ( int i = 0; i < nrpn.Length; i++ ) {
565+ VstEvent ve = new VstEvent();
566+ ve.deltaFrames = nrpn[i].Clock;
567+ ve[0] = 0xb0;
568+ ve[1] = nrpn[i].Parameter;
569+ ve[2] = nrpn[i].Value;
570+ ve.byteSize = 3;
571+ proc.Add( ve );
572+ }
573+ for ( int i = 0; i < tempo.Length; i++ ) {
574+ VstEvent ve = new VstEvent();
575+ ve.deltaFrames = tempo[i].Clock;
576+ ve[0] = 0xff;
577+ ve[1] = 0x51;
578+ ve[2] = 0x03;
579+ uint t = (uint)tempo[i].Tempo;
580+ ve[3] = (byte)(t >> 16);
581+ t = (uint)(t - (ve[3] << 16));
582+ ve[4] = (byte)(t >> 8);
583+ ve[5] = (byte)(t - (ve[4] << 8));
584+ ve.byteSize = 6;
585+ proc.Add( ve );
586+ }
587+ proc.Sort();
588+
589+ float[] left_ch_src = new float[s_sample_rate];
590+ float[] right_ch_src = new float[s_sample_rate];
591+ //float** out_buffer = { left_ch, right_ch };
592+
593+ //DWORD* wave_bufs;
594+ //wave_bufs = new DWORD[g_sampleRate];
595+
596+ SetSampleRate_( (float)s_sample_rate );
597+ MainsChanged_( 1 );
598+ SetBlockSize_( s_sample_rate );
599+
600+ int cur_buf = 0;
601+
602+ uint dwTempo = 500000;
603+
604+ int delay = 0;
605+ int duration = 0;
606+ uint dwNow = 0;
607+ uint dwPrev = 0;
608+ uint dwDelta;
609+ uint dwDelay = 0;
610+ uint dwDeltaDelay = 0;
611+
612+ int addr_msb = 0, addr_lsb = 0;
613+ int data_msb = 0, data_lsb = 0;
614+
615+#if DEBUG
616+ Console.WriteLine( "***********************************************************************" );
617+ int total_processed = 0;
618+#endif
619+
620+ //MIDI_EVENT* pWork = g_ppTrackEvents[1];
621+ int eof_clock = clEos;
622+ /*while ( !dwDelay && pWork ) {
623+ // Delayの取得
624+ if ( (pWork->pMidiEvent[0] & 0xf0) == 0xb0 ) {
625+ switch ( pWork->pMidiEvent[1] ) {
626+ case 0x63:
627+ addr_msb = pWork->pMidiEvent[2];
628+ addr_lsb = 0;
629+ break;
630+ case 0x62:
631+ addr_lsb = pWork->pMidiEvent[2];
632+ break;
633+ case 0x06:
634+ data_msb = pWork->pMidiEvent[2];
635+ break;
636+ case 0x26:
637+ data_lsb = pWork->pMidiEvent[2];
638+ if ( addr_msb == 0x50 && addr_lsb == 0x01 ) {
639+ delay = data_msb << 7 | data_lsb;
640+#if DEBUG
641+ Console.WriteLine( "delay=" + delay );
642+#endif
643+ dwDelay = (uint)(delay * (double)m_sample_rate / 1000.0);
644+ }
645+ break;
646+ }
647+ } else if ( pWork->pMidiEvent[0] == 0xff && pWork->pMidiEvent[1] == 0x2f && pWork->pMidiEvent[2] == 0x00 ) {
648+ eof_clock = pWork->clock;
649+#if DEBUG
650+ Console.WriteLine( "eof_clock=" + eof_clock );
651+#endif
652+ }
653+ pWork = pWork->pNext;
654+ }*/
655+
656+ int current_index = 0;
657+ while ( true ) {
658+#if DEBUG
659+ Console.WriteLine( "-----------------------------------------------------------------------" );
660+#endif
661+ //MIDI_EVENT* pProcessEvent = current;
662+ int nEvents = 0;
663+
664+ while ( proc[current_index].deltaFrames == dwNow ) {
665+ /*if ( current->pMidiEvent[0] == 0xFF ) {
666+ //メタイベントの処理
667+ switch ( current->pMidiEvent[1] ) {
668+ case 0x51:
669+ dwTempo = (uint)(current->pMidiEvent[5] | (current->pMidiEvent[4] << 8) | (current->pMidiEvent[3] << 16));
670+ break;
671+ }
672+ }*/
673+ // durationを取得
674+ if ( proc[current_index][0] == 0xb0 ) {
675+ switch ( proc[current_index][1] ) {
676+ case 0x63:
677+ addr_msb = proc[current_index][2];
678+ addr_lsb = 0;
679+ break;
680+ case 0x62:
681+ addr_lsb = proc[current_index][2];
682+ break;
683+ case 0x06:
684+ data_msb = proc[current_index][2];
685+ break;
686+ case 0x26:
687+ data_lsb = proc[current_index][2];
688+ // Note Duration in millisec
689+ if ( addr_msb == 0x50 && addr_lsb == 0x04 ) {
690+ duration = data_msb << 7 | data_lsb;
691+#if DEBUG
692+ Console.WriteLine( "duration=" + duration );
693+#endif
694+ }
695+ break;
696+ }
697+ }
698+
699+ nEvents++;
700+ current_index++;// = current->pNext;
701+ if ( current_index >= proc.Count ) {
702+ break;
703+ }
704+ }
705+
706+ if ( current_index >= proc.Count ) {
707+ break;
708+ }
709+
710+#if DEBUG
711+ Console.WriteLine( "nEvents=" + nEvents );
712+#endif
713+ double msNow = totalMilliSec_from_timeCode( dwNow, tempo );
714+ double msPrev = totalMilliSec_from_timeCode( dwPrev, tempo );
715+ //double dt = DeltaToMilliSecond( dwNow - dwPrev, dwTempo );
716+ double dt = msNow - msPrev;
717+ dwDelta = (uint)(dt * s_sample_rate / 1000.0);
718+#if DEBUG
719+ Console.WriteLine( "dwNow=" + dwNow );
720+ Console.WriteLine( "dwPrev=" + dwPrev );
721+ Console.WriteLine( "dt=" + dt );
722+ Console.WriteLine( "dwDelta=" + dwDelta );
723+#endif
724+
725+ //VstEvents* pVSTEvents = (VstEvents*)malloc( sizeof( VstEvents ) + nEvents * sizeof( VstEvent* ) );
726+ //pVSTEvents->numEvents = 0;
727+ //pVSTEvents->reserved = NULL;
728+
729+ VstEvent[] events = new VstEvent[nEvents];
730+ for ( int i = 0; i < nEvents; i++ ) {
731+ //BYTE event_code = pProcessEvent->pMidiEvent[0];
732+ //VstEvent* pVSTEvent = NULL;
733+ //VstMidiEvent* pMidiEvent;
734+
735+ /*switch ( event_code ) {
736+ case 0xff:
737+ break;
738+ case 0xf0:
739+ case 0xf7:
740+ break;
741+ default:
742+ pMidiEvent = (VstMidiEvent*)malloc( sizeof( VstMidiEvent ) + pProcessEvent->dwDataSize * sizeof( BYTE ) );
743+ pMidiEvent->byteSize = sizeof( VstMidiEvent );
744+ pMidiEvent->deltaFrames = dwDelta;
745+ pMidiEvent->detune = 0;
746+ pMidiEvent->flags = 1;
747+ pMidiEvent->noteLength = 0;
748+ pMidiEvent->noteOffset = 0;
749+ pMidiEvent->noteOffVelocity = 0;
750+ pMidiEvent->reserved1 = 0;
751+ pMidiEvent->reserved2 = 0;
752+ pMidiEvent->type = kVstMidiType;
753+ memcpy( &pMidiEvent->midiData, &pProcessEvent->pMidiEvent[pProcessEvent->dwOffset], pProcessEvent->dwDataSize );
754+ pVSTEvents->events[pVSTEvents->numEvents++] = (VstEvent*)pMidiEvent;
755+ break;
756+ }
757+ pProcessEvent = pProcessEvent->pNext;*/
758+ int index = current_index - nEvents + i + 1;
759+ events[i] = new VstEvent();
760+ events[i].flags = 0;
761+ events[i].type = 0;
762+ for ( int j = 0; j < proc[i].byteSize; j++ ) {
763+ events[i][j] = proc[index][j];
764+ }
765+ events[i].deltaFrames = (int)dwDelta;
766+ }
767+ fixed ( VstEvent* pVstEvent = &events[0] ) {
768+ ProcessEvents_( nEvents, pVstEvent );
769+ }
770+
771+ /*for ( int i = 0; i < pVSTEvents->numEvents; i++ ) {
772+ if ( pVSTEvents->events[i]->type == kVstSysExType ) {
773+ VstMidiSysexEvent* pSysexEvent = (VstMidiSysexEvent*)pVSTEvents->events[i];
774+ free( pSysexEvent->sysexDump );
775+ }
776+ }*/
777+
778+ while ( dwDelta > 0 ) {
779+ uint dwFrames = dwDelta > s_sample_rate ? (uint)s_sample_rate : dwDelta;
780+ fixed ( float* left = &left_ch_src[0] )
781+ fixed ( float* right = &right_ch_src[0] ) {
782+ float*[] bufa = new float*[] { left, right };
783+ fixed ( float** buf = &bufa[0] ) {
784+ ProcessReplacing_( buf, (int)dwFrames );
785+ }
786+ }
787+#if DEBUG
788+ for( int i = 0; i < left_ch_src.Length; i++ ){
789+ if ( i >= dwFrames ){
790+ break;
791+ }
792+ //Console.WriteLine( left_ch_src[i] );
793+ }
794+#endif
795+ /*for ( size_t j = 0; j < dwFrames; j++ ) {
796+ WORD right_chx = (WORD)(32768 * out_buffer[0][j]);
797+ WORD left_chx = (WORD)(32768 * out_buffer[1][j]);
798+ wave_bufs[j] = MAKELONG( right_chx, left_chx );
799+ }*/
800+
801+ int iOffset = (int)(dwDelay - dwDeltaDelay);
802+ if ( iOffset > dwFrames ) {
803+ iOffset = (int)dwFrames;
804+ }
805+ if ( iOffset == 0 ) {
806+ //mmioWrite( hmmio, (char*)wave_bufs, dwFrames * sizeof( DWORD ) );
807+ //mmioAscend( hmmio, &mmckData, 0 );
808+ } else {
809+ dwDeltaDelay += (uint)iOffset;
810+ }
811+#if DEBUG
812+ total_processed += (int)dwFrames;
813+#endif
814+ dwDelta -= dwFrames;
815+ }
816+
817+ //free( pVSTEvents );
818+
819+ dwPrev = dwNow;
820+ dwNow = (uint)nrpn[current_index].Clock; // current->clock;
821+ }
822+
823+#if DEBUG
824+ Console.WriteLine( "dwDeltaDelay=" + dwDeltaDelay );
825+#endif
826+ // dwDelta = g_sampleRate * (double)length / 1000.0 + dwDeltaDelay;
827+ double msLast = totalMilliSec_from_timeCode( dwNow, tempo );
828+ double msEof = totalMilliSec_from_timeCode( (uint)eof_clock, tempo );
829+ double msRemain = msEof - msLast;
830+ msRemain = (msRemain < 0.0) ? 0.0 : msRemain;
831+ uint dwDeltaDraft = (uint)(s_sample_rate * msRemain / 1000.0);
832+ dwDelta = (uint)(s_sample_rate * ((double)duration + (double)delay) / 1000.0 + dwDeltaDelay);
833+#if DEBUG
834+ Console.WriteLine( "dwDeltaDraft=" + dwDeltaDraft );
835+ Console.WriteLine( "dwDelta=" + dwDelta );
836+#endif
837+ dwDelta = (dwDelta > dwDeltaDraft) ? dwDelta : dwDeltaDraft;
838+ while ( dwDelta > 0 ) {
839+ uint dwFrames = dwDelta > (uint)s_sample_rate ? (uint)s_sample_rate : dwDelta;
840+ fixed ( float* left = &left_ch_src[0] )
841+ fixed ( float* right = &right_ch_src[0] ) {
842+ float*[] bufa = new float*[] { left, right };
843+ fixed ( float** buf = &bufa[0] ) {
844+ ProcessReplacing_( buf, (int)dwFrames );
845+ }
846+ }
847+ /*for ( size_t j = 0; j < dwFrames; j++ ) {
848+ WORD right_chx = (WORD)(32768 * out_buffer[0][j]);
849+ WORD left_chx = (WORD)(32768 * out_buffer[1][j]);
850+ wave_bufs[j] = MAKELONG( right_chx, left_chx );
851+ }*/
852+#if DEBUG
853+ for( int i = 0; i < left_ch_src.Length; i++ ){
854+ if ( i >= dwFrames ){
855+ break;
856+ }
857+ //Console.WriteLine( left_ch_src[i] );
858+ }
859+#endif
860+
861+ //mmioWrite( hmmio, (char*)wave_bufs, dwFrames * sizeof( DWORD ) );
862+ //mmioAscend( hmmio, &mmckData, 0 );
863+
864+ dwDelta -= dwFrames;
865+#if DEBUG
866+ total_processed += (int)dwFrames;
867+#endif
868+ }
869+
870+ MainsChanged_( 0 );// g_pAEffect->dispatcher( g_pAEffect, effMainsChanged, 0, 0, 0, 0 );
871+
872+ //mmioAscend( hmmio, &mmckRiff, 0 );
873+ //mmioClose( hmmio, 0 );
874+
875+ //free_events( lpEvents );
876+ //delete[] left_ch;
877+ //delete[] right_ch;
878+ //delete[] wave_bufs;
879+#if DEBUG
880+ Console.WriteLine( "total_processed=" + total_processed );
881+#endif
882+
883+ return 1;
884+ }
885+
886+ public static void AbortRendering() {
887+ try {
888+ AbortRendering_();
889+ } catch ( Exception ex ) {
890+#if TEST
891+ bocoree.debug.PushLog( "VSTiProxy+AbortRendering()" );
892+ bocoree.debug.PushLog( " ex=" + ex.ToString() );
893+#endif
894+ }
895+ }
896+
897+ private static bool LoadPlugin( int blockSize, int sampleRate ) {
898+ s_dll_path = VsqUtil.VstiDllPath;
899+#if TEST
900+ bocoree.debug.PushLog( "VSTiProxy+LoadPlugin(String, Int32, Int32)" );
901+ bocoree.debug.PushLog( " m_dll_path=" + s_dll_path );
902+#endif
903+ if ( s_dll_path == "" ) {
904+ s_loaded = false;
905+ return false;
906+ }
907+ if ( s_error_counter > NUM_ERR_THRESHOLD ) {
908+ //throw new ApplicationException();
909+ return false;
910+ }
911+ int ret = 0;
912+ try {
913+ ret = LoadPluginW_( s_dll_path, blockSize, sampleRate );
914+ s_loaded = true;
915+ return true;
916+ } catch ( Exception ex ) {
917+#if TEST
918+ bocoree.debug.PushLog( ex.ToString() );
919+#endif
920+ s_error_counter++;
921+ }
922+ if ( ret == 0 ) {
923+ s_error_counter++;
924+ }
925+ return false;
926+ }
927+
928+ private static bool FreePlugin() {
929+ if ( s_loaded ) {
930+ try {
931+ int ret = FreePlugin_();
932+ if ( ret == 0 ) {
933+ return false;
934+ } else {
935+ return true;
936+ }
937+ } catch ( Exception ex ) {
938+#if TEST
939+ bocoree.debug.PushLog( "VSTiProxy+FreePlugin()" );
940+ bocoree.debug.PushLog( " ex=" + ex.ToString() );
941+#endif
942+ }
943+ }
944+ return false;
945+ }
946+
947+ public unsafe static void SendEvent( byte* src, int* deltaFrames, int numEvents, VSTiProxyTrackType targetTrack ) {
948+ if ( s_loaded ) {
949+ int track = targetTrack == VSTiProxyTrackType.TempoTrack ? 0 : 1;
950+ try {
951+ int ret = SendEvent_( src, deltaFrames, numEvents, track );
952+ if ( ret == 0 ) {
953+ //throw new ApplicationException();
954+ }
955+ } catch ( Exception ex ) {
956+#if TEST
957+ bocoree.debug.PushLog( "VSTiProxy+SendEvent(byte*, int*, int, VSTiProxyTrackType)" );
958+ bocoree.debug.PushLog( " ex=" + ex.ToString() );
959+#endif
960+ }
961+ }
962+ }
963+
964+ public static bool RenderToWave( string name, uint eof_clock ) {
965+ try {
966+ int ret = RenderToWaveW_( name, eof_clock );
967+ if ( ret == 0 ) {
968+ return false;
969+ }
970+ return true;
971+ } catch ( Exception ex ) {
972+#if TEST
973+ bocoree.debug.PushLog( "VSTiProxy+RenderToWave(string, uint)" );
974+ bocoree.debug.PushLog( " ex=" + ex.ToString() );
975+#endif
976+ }
977+ return false;
978+ }
979+
980+ public static void Finalize() {
981+ AbortRendering();
982+ if ( s_loaded ) {
983+ FreePlugin();
984+ s_loaded = false;
985+ }
986+ }
987+
988+ public static unsafe bool RenderToWave( NrpnData[] nrpn, TempoTableEntry[] tempo, int clEos, string file ) {
989+#if TEST
990+ Console.WriteLine( "VSTiProxy.RenderToWave( NRPN[], TempoTableEntry[], int, string )" );
991+ bocoree.debug.PushLog( "VSTiPRoxy+RenderToWave(NrpnData[], TempoTableEntry[], int, string)" );
992+#endif
993+ if ( !s_loaded ) {
994+ s_loaded = LoadPlugin( 44100, 44100 );
995+ }
996+ if ( !s_loaded ) {
997+ return false;
998+ }
999+ int tempo_count = tempo.Length;
1000+ byte[] masterEventsSrc = new byte[tempo_count * 3];
1001+ int[] masterClocksSrc = new int[tempo_count];
1002+ int count = -3;
1003+ for ( int i = 0; i < tempo.Length; i++ ) {
1004+ count += 3;
1005+ masterClocksSrc[i] = tempo[i].Clock;
1006+ byte b0 = (byte)(tempo[i].Tempo >> 16);
1007+ uint u0 = (uint)(tempo[i].Tempo - (b0 << 16));
1008+ byte b1 = (byte)(u0 >> 8);
1009+ byte b2 = (byte)(u0 - (u0 << 8));
1010+#if DEBUG
1011+ Console.WriteLine( " b0-b2=0x" + Convert.ToString( b0, 16 ) + ", 0x" + Convert.ToString( b1, 16 ) + ", 0x" + Convert.ToString( b2, 16 ) );
1012+#endif
1013+ masterEventsSrc[count] = b0;
1014+ masterEventsSrc[count + 1] = b1;
1015+ masterEventsSrc[count + 2] = b2;
1016+ }
1017+ fixed ( byte* masterEvents = &masterEventsSrc[0] )
1018+ fixed ( int* masterClocks = &masterClocksSrc[0] ) {
1019+ SendEvent( masterEvents, masterClocks, tempo_count, VSTiProxyTrackType.TempoTrack );
1020+ }
1021+
1022+ int numEvents = nrpn.Length + 1;
1023+ byte[] bodyEventsSrc = new byte[numEvents * 3];
1024+ int[] bodyClocksSrc = new int[numEvents];
1025+ count = -3;
1026+ int last_clock = 0;
1027+#if DEBUG
1028+ string test = Path.Combine( Path.GetDirectoryName( file ), Path.GetFileNameWithoutExtension( file ) + ".txt" );
1029+ StreamWriter sw = new StreamWriter( test, false );
1030+#endif
1031+ for ( int i = 0; i < numEvents - 1; i++ ) {
1032+ count += 3;
1033+ bodyEventsSrc[count] = 0xb0;
1034+ bodyEventsSrc[count + 1] = nrpn[i].Parameter;
1035+ bodyEventsSrc[count + 2] = nrpn[i].Value;
1036+ bodyClocksSrc[i] = nrpn[i].Clock;
1037+ last_clock = nrpn[i].Clock;
1038+#if DEBUG
1039+ sw.WriteLine( nrpn[i].Clock + "\t0x" + Convert.ToString( nrpn[i].Parameter, 16 ) + "\t0x" + Convert.ToString( nrpn[i].Value, 16 ) );
1040+#endif
1041+ }
1042+#if DEBUG
1043+ sw.Close();
1044+#endif
1045+ count += 3;
1046+ bodyEventsSrc[count] = 0xff;
1047+ bodyEventsSrc[count + 1] = 0x2f;
1048+ bodyEventsSrc[count + 2] = 0x00;
1049+ bodyClocksSrc[numEvents - 1] = clEos;
1050+ int index = tempo_count - 1;
1051+ for ( int i = tempo_count - 1; i >= 0; i-- ) {
1052+ if ( tempo[i].Clock < last_clock ) {
1053+ index = i;
1054+ break;
1055+ }
1056+ }
1057+ int last_tempo = tempo[index].Tempo;
1058+
1059+ fixed ( byte* bodyEvents = &bodyEventsSrc[0] )
1060+ fixed ( int* bodyClocks = &bodyClocksSrc[0] ) {
1061+ SendEvent( bodyEvents, bodyClocks, numEvents, VSTiProxyTrackType.MainTrack );
1062+ }
1063+ return RenderToWave( file, (uint)clEos );
1064+ }
1065+
1066+ public static unsafe void GenerateSinglePhone( int note, byte program_change, string file ) {
1067+#if TEST
1068+ Common.DebugWriteLine( "VSTiProxy+GenerateSinglePhone" );
1069+ Common.DebugWriteLine( " program_change=" + program_change );
1070+#endif
1071+ #region pre-set data
1072+ NrpnData[] nrps = new NrpnData[]{
1073+ new NrpnData( 0, 0x63, 0x60 ),
1074+ new NrpnData( 0, 0x62, 0x00 ),
1075+ new NrpnData( 0, 0x06, 0x00 ),
1076+ new NrpnData( 0, 0x26, 0x00 ),
1077+ new NrpnData( 0, 0x63, 0x60 ),
1078+ new NrpnData( 0, 0x62, 0x01 ),
1079+ new NrpnData( 0, 0x06, 0x00 ),
1080+ new NrpnData( 0, 0x26, 0x00 ),
1081+ new NrpnData( 0, 0x63, 0x60 ),
1082+ new NrpnData( 0, 0x62, 0x02 ),
1083+ new NrpnData( 0, 0x06, 0x00 ),
1084+ new NrpnData( 0, 0x63, 0x53 ),
1085+ new NrpnData( 0, 0x62, 0x02 ),
1086+ new NrpnData( 0, 0x06, program_change ),
1087+ new NrpnData( 286, 0x63, 0x50 ),
1088+ new NrpnData( 286, 0x62, 0x01 ),
1089+ new NrpnData( 286, 0x06, 0x02 ),
1090+ new NrpnData( 286, 0x26, 0x47 ),
1091+ new NrpnData( 286, 0x62, 0x02 ),
1092+ new NrpnData( 286, 0x06, (byte)note ),
1093+ new NrpnData( 286, 0x62, 0x03 ),
1094+ new NrpnData( 286, 0x06, 0x40 ),
1095+ new NrpnData( 286, 0x62, 0x04 ),
1096+ new NrpnData( 286, 0x06, 0x03 ),
1097+ new NrpnData( 286, 0x26, 0x74 ),
1098+ new NrpnData( 286, 0x62, 0x05 ),
1099+ new NrpnData( 286, 0x06, 0x03 ),
1100+ new NrpnData( 286, 0x62, 0x12 ),
1101+ new NrpnData( 286, 0x06, 0x01 ),
1102+ new NrpnData( 286, 0x62, 0x13 ),
1103+ new NrpnData( 286, 0x06, 0x61 ),
1104+ new NrpnData( 286, 0x26, 0x00 ),
1105+ new NrpnData( 286, 0x62, 0x4F ),
1106+ new NrpnData( 286, 0x06, 0x7F ),
1107+ new NrpnData( 286, 0x62, 0x50 ),
1108+ new NrpnData( 286, 0x06, 0x04 ),
1109+ new NrpnData( 286, 0x62, 0x51 ),
1110+ new NrpnData( 286, 0x06, 0x08 ),
1111+ new NrpnData( 286, 0x62, 0x52 ),
1112+ new NrpnData( 286, 0x06, 0x14 ),
1113+ new NrpnData( 286, 0x62, 0x53 ),
1114+ new NrpnData( 286, 0x06, 0x1C ),
1115+ new NrpnData( 286, 0x62, 0x54 ),
1116+ new NrpnData( 286, 0x06, 0x18 ),
1117+ new NrpnData( 286, 0x62, 0x55 ),
1118+ new NrpnData( 286, 0x06, 0x0A ),
1119+ new NrpnData( 286, 0x62, 0x56 ),
1120+ new NrpnData( 286, 0x06, 0x0C ),
1121+ new NrpnData( 286, 0x62, 0x57 ),
1122+ new NrpnData( 286, 0x06, 0x0C ),
1123+ new NrpnData( 286, 0x62, 0x58 ),
1124+ new NrpnData( 286, 0x06, 0x00 ),
1125+ new NrpnData( 286, 0x62, 0x59 ),
1126+ new NrpnData( 286, 0x06, 0x32 ),
1127+ new NrpnData( 286, 0x62, 0x5A ),
1128+ new NrpnData( 286, 0x06, 0x32 ),
1129+ new NrpnData( 286, 0x62, 0x7F ),
1130+ new NrpnData( 286, 0x06, 0x7F ),
1131+ };
1132+ #endregion
1133+ if ( !s_loaded ) {
1134+ try {
1135+ s_loaded = LoadPlugin( 44100, 44100 );
1136+ } catch ( Exception ex ) {
1137+#if TEST
1138+ bocoree.debug.PushLog( ex.ToString() );
1139+#endif
1140+ return;
1141+ }
1142+ if ( !s_loaded ) {
1143+ return;
1144+ }
1145+ }
1146+ byte[] masterEventsSrc = new byte[3];
1147+ masterEventsSrc[0] = 0x07;
1148+ masterEventsSrc[1] = 0xa1;
1149+ masterEventsSrc[2] = 0x20;
1150+ int[] masterClocksSrc = new int[1];
1151+ masterClocksSrc[0] = 0;
1152+ fixed ( byte* masterEvents = &masterEventsSrc[0] )
1153+ fixed ( int* masterClocks = &masterClocksSrc[0] ) {
1154+ SendEvent( masterEvents, masterClocks, 1, VSTiProxyTrackType.TempoTrack );
1155+ }
1156+
1157+ int numEvents = nrps.Length + 1;
1158+ byte[] bodyEventsSrc = new byte[numEvents * 3];
1159+ int[] bodyClocksSrc = new int[numEvents];
1160+ int count = -3;
1161+ //nrps[17].Value = (byte)note;
1162+ for ( int i = 0; i < numEvents - 1; i++ ) {
1163+ count += 3;
1164+ bodyEventsSrc[count] = 0xb0;
1165+ bodyEventsSrc[count + 1] = nrps[i].Parameter;
1166+ bodyEventsSrc[count + 2] = nrps[i].Value;
1167+ bodyClocksSrc[i] = nrps[i].Clock;
1168+ }
1169+ count += 3;
1170+ bodyEventsSrc[count] = 0xff;
1171+ bodyEventsSrc[count + 1] = 0x2f;
1172+ bodyEventsSrc[count + 2] = 0x00;
1173+ bodyClocksSrc[numEvents - 1] = 2280;
1174+ fixed ( byte* bodyEvents = &bodyEventsSrc[0] )
1175+ fixed ( int* bodyClocks = &bodyClocksSrc[0] ) {
1176+ SendEvent( bodyEvents, bodyClocks, numEvents, VSTiProxyTrackType.MainTrack );
1177+ }
1178+
1179+ RenderToWave( file, 2280 );
1180+ }
1181+ }
1182+}
旧リポジトリブラウザで表示