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); } } } } }
/// <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); }