アンマネージドなメモリーの確保・解放を行うマネージャです。
Example #1
0
        public virtual void send( MidiEvent[] events )
        {
            if ( events.Length == 0 ) return;
            unsafe {
                MemoryManager mman = null;
                try {
                    mman = new MemoryManager();
                    int nEvents = events.Length;
                    VstEvents* pVSTEvents = (VstEvents*)mman.malloc( sizeof( VstEvent ) + nEvents * sizeof( VstEvent* ) ).ToPointer();
                    pVSTEvents->numEvents = 0;
                    pVSTEvents->reserved = (VstIntPtr)0;

                    for ( int i = 0; i < nEvents; i++ ) {
                        MidiEvent pProcessEvent = events[i];
                        //byte event_code = (byte)pProcessEvent.firstByte;
                        VstEvent* pVSTEvent = (VstEvent*)0;
                        VstMidiEvent* pMidiEvent;
                        pMidiEvent = (VstMidiEvent*)mman.malloc( (int)(sizeof( VstMidiEvent ) + (pProcessEvent.data.Length + 1) * sizeof( byte )) ).ToPointer();
                        pMidiEvent->byteSize = sizeof( VstMidiEvent );
                        pMidiEvent->deltaFrames = 0;
                        pMidiEvent->detune = 0;
                        pMidiEvent->flags = 1;
                        pMidiEvent->noteLength = 0;
                        pMidiEvent->noteOffset = 0;
                        pMidiEvent->noteOffVelocity = 0;
                        pMidiEvent->reserved1 = 0;
                        pMidiEvent->reserved2 = 0;
                        pMidiEvent->type = VstEventTypes.kVstMidiType;
                        pMidiEvent->midiData[0] = (byte)(0xff & pProcessEvent.firstByte);
                        for ( int j = 0; j < pProcessEvent.data.Length; j++ ) {
                            pMidiEvent->midiData[j + 1] = (byte)(0xff & pProcessEvent.data[j]);
                        }
                        pVSTEvents->events[pVSTEvents->numEvents++] = (int)(VstEvent*)pMidiEvent;
                    }
                    aEffect.Dispatch( AEffectXOpcodes.effProcessEvents, 0, 0, new IntPtr( pVSTEvents ), 0 );
                } catch ( Exception ex ) {
                    serr.println( "vstidrv#send; ex=" + ex );
                } finally {
                    if ( mman != null ) {
                        try {
                            mman.dispose();
                        } catch ( Exception ex2 ) {
                            serr.println( "vstidrv#send; ex2=" + ex2 );
                        }
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="total_samples"></param>
        /// <param name="mode_infinite"></param>
        /// <param name="sample_rate"></param>
        /// <param name="runner">このドライバを駆動しているRenderingRunnerのオブジェクト</param>
        /// <returns></returns>
        public int startRendering( long total_samples, boolean mode_infinite, int sample_rate, IWaveIncoming runner, WorkerState state )
        {
#if DEBUG
            sout.println( "VocaloidDriver#startRendering; entry; total_samples=" + total_samples + "; sample_rate=" + sample_rate );
#endif
            lock ( locker ) {
                rendering = true;
                //g_cancelRequired = false;
                g_progress = 0.0;
                sampleRate = sample_rate;

                Vector<MidiEvent> lpEvents = merge_events( s_track_events.get( 0 ), s_track_events.get( 1 ) );
                int current_count = -1;
                MidiEvent current = new MidiEvent();// = lpEvents;

                MemoryManager mman = null;
                float* left_ch;
                float* right_ch;
                float** out_buffer;
                try {
                    mman = new MemoryManager();
                    left_ch = (float*)mman.malloc( sizeof( float ) * sampleRate ).ToPointer();
                    right_ch = (float*)mman.malloc( sizeof( float ) * sampleRate ).ToPointer();
                    out_buffer = (float**)mman.malloc( sizeof( float* ) * 2 ).ToPointer();
                    out_buffer[0] = left_ch;
                    out_buffer[1] = right_ch;

                    double[] buffer_l = new double[sampleRate];
                    double[] buffer_r = new double[sampleRate];

#if TEST
                    org.kbinani.debug.push_log( "    calling initial dispatch..." );
#endif
#if DEBUG
                    sout.println( "VocaloidDriver#startRendering; sampleRate=" + sampleRate );
#endif
                    aEffect.Dispatch( AEffectOpcodes.effSetSampleRate, 0, 0, IntPtr.Zero, (float)sampleRate );
                    aEffect.Dispatch( AEffectOpcodes.effMainsChanged, 0, 1, IntPtr.Zero, 0 );

                    // ここではブロックサイズ=サンプリングレートということにする
                    aEffect.Dispatch( AEffectOpcodes.effSetBlockSize, 0, sampleRate, IntPtr.Zero, 0 );

                    // レンダリングの途中で停止した場合,ここでProcessする部分が無音でない場合がある
                    for ( int i = 0; i < 3; i++ ) {
                        aEffect.ProcessReplacing( IntPtr.Zero, new IntPtr( out_buffer ), sampleRate );
                    }
#if TEST
                    org.kbinani.debug.push_log( "    ...done" );
#endif

                    int delay = 0;
                    int duration = 0;
                    int dwNow = 0;
                    int dwPrev = 0;
                    int dwDelta;
                    int dwDelay = 0;
                    int dwDeltaDelay = 0;

                    int addr_msb = 0, addr_lsb = 0;
                    int data_msb = 0, data_lsb = 0;

                    int total_processed = 0;
                    int total_processed2 = 0;
#if TEST
                    org.kbinani.debug.push_log( "    getting dwDelay..." );
#endif
                    dwDelay = 0;
                    Vector<MidiEvent> list = s_track_events.get( 1 );
                    int list_size = list.size();
                    for ( int i = 0; i < list_size; i++ ) {
                        MidiEvent work = list.get( i );
                        if ( (work.firstByte & 0xf0) == 0xb0 ) {
                            switch ( work.data[0] ) {
                                case 0x63:
                                addr_msb = work.data[1];
                                addr_lsb = 0;
                                break;
                                case 0x62:
                                addr_lsb = work.data[1];
                                break;
                                case 0x06:
                                data_msb = work.data[1];
                                break;
                                case 0x26:
                                data_lsb = work.data[1];
                                if ( addr_msb == 0x50 && addr_lsb == 0x01 ) {
                                    dwDelay = (data_msb & 0xff) << 7 | (data_lsb & 0x7f);
                                }
                                break;
                            }
                        }
                        if ( dwDelay > 0 ) {
                            break;
                        }
                    }
#if TEST
                    org.kbinani.debug.push_log( "    ...done; dwDelay=" + dwDelay );
#endif

                    while ( !state.isCancelRequested() ) {
                        int process_event_count = current_count;
                        int nEvents = 0;

#if TEST
                        org.kbinani.debug.push_log( "lpEvents.Count=" + lpEvents.size() );
#endif
                        if ( current_count < 0 ) {
                            current_count = 0;
                            current = lpEvents.get( current_count );
                            process_event_count = current_count;
                        }
                        while ( current.clock == dwNow ) {
                            // durationを取得
                            if ( (current.firstByte & 0xf0) == 0xb0 ) {
                                switch ( current.data[0] ) {
                                    case 0x63:
                                    addr_msb = current.data[1];
                                    addr_lsb = 0;
                                    break;
                                    case 0x62:
                                    addr_lsb = current.data[1];
                                    break;
                                    case 0x06:
                                    data_msb = current.data[1];
                                    break;
                                    case 0x26:
                                    data_lsb = current.data[1];
                                    // Note Duration in millisec
                                    if ( addr_msb == 0x50 && addr_lsb == 0x4 ) {
                                        duration = data_msb << 7 | data_lsb;
                                    }
                                    break;
                                }
                            }

                            nEvents++;
                            if ( current_count + 1 < lpEvents.size() ) {
                                current_count++;
                                current = lpEvents.get( current_count );
                            } else {
                                break;
                            }
                        }

                        if ( current_count + 1 >= lpEvents.size() ) {
                            break;
                        }

                        double msNow = msec_from_clock( dwNow );
                        dwDelta = (int)(msNow / 1000.0 * sampleRate) - total_processed;
#if TEST
                    org.kbinani.debug.push_log( "dwNow=" + dwNow );
                    org.kbinani.debug.push_log( "dwPrev=" + dwPrev );
                    org.kbinani.debug.push_log( "dwDelta=" + dwDelta );
#endif
                        VstEvents* pVSTEvents = (VstEvents*)mman.malloc( sizeof( VstEvent ) + nEvents * sizeof( VstEvent* ) ).ToPointer();
                        pVSTEvents->numEvents = 0;
                        pVSTEvents->reserved = (VstIntPtr)0;

                        for ( int i = 0; i < nEvents; i++ ) {
                            MidiEvent pProcessEvent = lpEvents.get( process_event_count );
                            int event_code = pProcessEvent.firstByte;
                            VstEvent* pVSTEvent = (VstEvent*)0;
                            VstMidiEvent* pMidiEvent;

                            switch ( event_code ) {
                                case 0xf0:
                                case 0xf7:
                                case 0xff:
                                break;
                                default:
                                pMidiEvent = (VstMidiEvent*)mman.malloc( (int)(sizeof( VstMidiEvent ) + (pProcessEvent.data.Length + 1) * sizeof( byte )) ).ToPointer();
                                pMidiEvent->byteSize = sizeof( VstMidiEvent );
                                pMidiEvent->deltaFrames = dwDelta;
                                pMidiEvent->detune = 0;
                                pMidiEvent->flags = 1;
                                pMidiEvent->noteLength = 0;
                                pMidiEvent->noteOffset = 0;
                                pMidiEvent->noteOffVelocity = 0;
                                pMidiEvent->reserved1 = 0;
                                pMidiEvent->reserved2 = 0;
                                pMidiEvent->type = VstEventTypes.kVstMidiType;
                                pMidiEvent->midiData[0] = (byte)(0xff & pProcessEvent.firstByte);
                                for ( int j = 0; j < pProcessEvent.data.Length; j++ ) {
                                    pMidiEvent->midiData[j + 1] = (byte)(0xff & pProcessEvent.data[j]);
                                }
                                pVSTEvents->events[pVSTEvents->numEvents++] = (int)(VstEvent*)pMidiEvent;
                                break;
                            }
                            process_event_count++;
                            //pProcessEvent = lpEvents[process_event_count];
                        }
#if TEST
                        org.kbinani.debug.push_log( "calling Dispatch with effProcessEvents..." );
#endif
                        aEffect.Dispatch( AEffectXOpcodes.effProcessEvents, 0, 0, new IntPtr( pVSTEvents ), 0 );
#if TEST
                        org.kbinani.debug.push_log( "...done" );
#endif

                        while ( dwDelta > 0 && !state.isCancelRequested() ) {
                            int dwFrames = dwDelta > sampleRate ? sampleRate : dwDelta;
#if TEST
                            org.kbinani.debug.push_log( "calling ProcessReplacing..." );
#endif
                            aEffect.ProcessReplacing( IntPtr.Zero, new IntPtr( out_buffer ), dwFrames );
#if TEST
                            org.kbinani.debug.push_log( "...done" );
#endif

                            int iOffset = dwDelay - dwDeltaDelay;
                            if ( iOffset > (int)dwFrames ) {
                                iOffset = (int)dwFrames;
                            }

                            if ( iOffset == 0 ) {
                                for ( int i = 0; i < (int)dwFrames; i++ ) {
                                    buffer_l[i] = out_buffer[0][i];
                                    buffer_r[i] = out_buffer[1][i];
                                }
                                total_processed2 += dwFrames;
                                runner.waveIncomingImpl( buffer_l, buffer_r, dwFrames, state );
                            } else {
                                dwDeltaDelay += iOffset;
                            }
                            dwDelta -= dwFrames;
                            total_processed += dwFrames;
                        }

                        dwPrev = dwNow;
                        dwNow = (int)current.clock;
                        g_progress = total_processed / (double)total_samples * 100.0;
                    }

                    double msLast = msec_from_clock( dwNow );
                    dwDelta = (int)(sampleRate * ((double)duration + (double)delay) / 1000.0 + dwDeltaDelay);
                    if ( total_samples - total_processed2 > dwDelta ) {
                        dwDelta = (int)total_samples - total_processed2;
                    }
                    while ( dwDelta > 0 && !state.isCancelRequested() ) {
                        int dwFrames = dwDelta > sampleRate ? sampleRate : dwDelta;
#if TEST
                        org.kbinani.debug.push_log( "calling ProcessReplacing..." );
#endif
                        aEffect.ProcessReplacing( IntPtr.Zero, new IntPtr( out_buffer ), dwFrames );
#if TEST
                        org.kbinani.debug.push_log( "...done" );
#endif

                        for ( int i = 0; i < (int)dwFrames; i++ ) {
                            buffer_l[i] = out_buffer[0][i];
                            buffer_r[i] = out_buffer[1][i];
                        }
                        total_processed2 += dwFrames;
                        runner.waveIncomingImpl( buffer_l, buffer_r, dwFrames, state );

                        dwDelta -= dwFrames;
                        total_processed += dwFrames;
                    }

#if TEST
                    sout.println( "vstidrv::StartRendering; total_processed=" + total_processed );
#endif

                    if ( mode_infinite ) {
                        for ( int i = 0; i < sampleRate; i++ ) {
                            buffer_l[i] = 0.0;
                            buffer_r[i] = 0.0;
                        }
                        while ( !state.isCancelRequested() ) {
                            total_processed2 += sampleRate;
                            runner.waveIncomingImpl( buffer_l, buffer_r, sampleRate, state );
                        }
                    }

                    aEffect.Dispatch( AEffectOpcodes.effMainsChanged, 0, 0, IntPtr.Zero, 0 );
                    lpEvents.clear();
#if DEBUG
                    sout.println( "VocaloidDriver#startRendering; done; total_processed=" + total_processed + "; total_processed2=" + total_processed2 );
#endif
                } catch ( Exception ex ) {
                    serr.println( "VocaloidDriver#startRendering; ex=" + ex );
                } finally {
                    if ( mman != null ) {
                        try {
                            mman.dispose();
                        } catch ( Exception ex2 ) {
                            serr.println( "VocaloidDriver#startRendering; ex2=" + ex2 );
                        }
                    }
                }
                rendering = false;
                g_saProcessed = 0;
                for ( int i = 0; i < s_track_events.size(); i++ ) {
                    s_track_events.get( i ).clear();
                }
                g_tempoList.clear();
                //g_cancelRequired = false;
            }
            return 1;
        }