2016-02-16 6 views
0

Мне нужно синхронизировать некоторые ничьи с OpenGL с метроном. Metronome построен с помощью libPD и воспроизводится с RtAudio. Обе вещи работают хорошо (отдельно), но мне нужно переместить объект (треугольник) с импульсом метроном. Приложение также должно воспроизводить клики. Оба действия должны выполняться параллельно (воспроизведение и рисование). Я должен добавить миди-запись. Мое приложение находится на C++. Я попытался запустить это с помощью одного потока, но он не работает. Я попытался следовать этому объяснению: How to make my metronome play at the same time as recording in my program? Gui Library - WxWidgets. Нити сделаны с Poco :: Runnable таким образом:Синхронизация OpenGL с RtAudio (или звуком порта)

class MyThread : public Poco::Runnable { 
public: 
    MyThread(BasicGLPane *pane, std::shared_ptr<SoundManager> man); 

    virtual void run(); 
private: 
    BasicGLPane *_pane; 
    std::shared_ptr<SoundManager> _man; 
}; 

MyThread::MyThread(BasicGLPane *pane, std::shared_ptr<SoundManager> man) { 
    _pane = pane; 
    _man = man; 
} 


void MyThread::run() { 
    _man->play(); 
    _pane->startAnimation();  
} 

BasicGLpane является wxGLCanvas. Пьеса функция класса Sound Manager заключается в следующем:

void SoundManager::play() { 
    // Init pd 
    if(!lpd->init(0, 2, sampleRate)) { 
     std::cerr << "Could not init pd" << std::endl; 
     exit(1); 
    }  
    // Receive messages from pd 
    lpd->setReceiver(object.get()); 
    lpd->subscribe("metro-bang"); 
    lpd->subscribe("switch"); 

    // send DSP 1 message to pd 
    lpd->computeAudio(true); 

    // load the patch 
    open_patch("metro-main.pd"); 
    std::cout << patch << std::endl;  

    // Use the RtAudio API to connect to the default audio device. 
    if(audio->getDeviceCount()==0){ 
     std::cout << "There are no available sound devices." << std::endl; 
     exit(1); 
    } 

    RtAudio::StreamParameters parameters; 
    parameters.deviceId = audio->getDefaultOutputDevice(); 
    parameters.nChannels = 2; 

    RtAudio::StreamOptions options; 
    options.streamName = "Pd Metronome"; 
    options.flags = RTAUDIO_SCHEDULE_REALTIME; 
    if (audio->getCurrentApi() != RtAudio::MACOSX_CORE) { 
     options.flags |= RTAUDIO_MINIMIZE_LATENCY; // CoreAudio doesn't seem to like this 
    } 
    try { 
     if(audio->isStreamOpen()) { 
      audio->closeStream(); 
     } 
     else { 
      audio->openStream(&parameters, NULL, RTAUDIO_FLOAT32, sampleRate, &bufferFrames, &audioCallback, lpd.get(), &options); 
      audio->startStream(); 
     } 
    } 
    catch (RtAudioError& e) { 
     std::cerr << e.getMessage() << std::endl; 
     exit(1); 
    } 
} 

OpenGL рисунок METHODE являются следующие:

void BasicGLPane::startAnimation() { 
    std::cout<<"Start Animation"<<std::endl; 
    triangle_1(p1, p2, p3);  
    Refresh(); 
} 

void BasicGLPane::triangle_1(std::shared_ptr<vertex2f> _p1, std::shared_ptr<vertex2f> _p2, std::shared_ptr<vertex2f> _p3) { 
    CGLContextObj ctx = CGLGetCurrentContext(); //enable multithreading (only apple) 
    CGLError err = CGLEnable(ctx, kCGLCEMPEngine); 
    if (err != kCGLNoError) { 
     glEnable(GL_MULTISAMPLE); 
     glMatrixMode(GL_PROJECTION); 
     glLoadIdentity(); 
     glOrtho(0, getWidth(), getHeight(),0 , -1, 1); 
     glShadeModel(GL_SMOOTH); 
     glBegin(GL_POLYGON);      // Drawing Using Triangles 
     glColor3f (157.0/255.0, 44.0/255.0, 44.0/255.0); 
     glVertex3f(p1->x, p1->y, 0.0f);    // Top left 
     glVertex3f(p2->x,p2->y, 0.0f);    // Top Right 
     glVertex3f(p3->x,p3->y, 0.0f);    //Bottom 
     glEnd(); 
     glMatrixMode(GL_MODELVIEW); 
     glEnable (GL_BLEND); 
     glLoadIdentity(); 
     glDisable(GL_MULTISAMPLE); 
    } 
} 

И нить звонит со следующим несильно:

void BasicGLPane::startThread() { 
    while (_object->getCounter()<10) { //this is only to test the functionality 
     thread.start(work); 
    } 
    thread.join(); 
    manager->stop(); 
} 

И после этого этот funtion вызывается в Редире:

void BasicGLPane::render(wxPaintEvent& evt) { 
    //some code here, not important.... 
    startThread(); 
    SwapBuffers(); 
} 

Возможно, я собираюсь изменить этот объект, это не важно сейчас, моя проблема в синхронизации. Я думаю, что RtAudio создает проблемы, потому что я становлюсь EXC_BAD_Acces для getDeviceCount() или любой другой функцией из RtAudio. Это происходит только в контексте потока. Было бы лучше сделать это с помощью Port Audio ?. Было бы неплохо узнать, что я делаю неправильно, или если есть другой способ решить эту проблему.

ответ

0

Я нашел решение. Проблема заключалась во взаимодействии между WxWidgets основного циклом и решениями openGL.The является создание Idle события ИНТА следующим образом:

//on wxApp 
void MyApp::activateRenderLoop(bool on) { 
    if(on && !render_loop_on) { 
     Connect(wxID_ANY, wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle)); 
     render_loop_on = true; 
    } 
    else if (!on && render_loop_on) { 
     Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle)); 
     render_loop_on = false; 
    } 
} 

void MyApp::onIdle(wxIdleEvent &evt) { 
    activateRenderLoop(glPane->render_on); 
    if(render_loop_on) { 
     std::cout<<"MyApp on Idle, render_loop_on"<<std::endl; 
     glPane->paint_now(); 
     evt.RequestMore(); 
    } 
} 

//on event table: 
EVT_PAINT(BasicGLPane::paint_rt) 

void BasicGLPane::rightClick(wxMouseEvent& event) { 
    render_on = true; 
    manager->init(); 
    SLEEP(2000); 
    manager->play(); 
    wxGetApp().activateRenderLoop(true); 
} 

void BasicGLPane::paint_rt(wxPaintEvent &evt) { 
    wxPaintDC dc(this); 
    render_rt(dc); 
} 

void BasicGLPane::paint_now(){ 
    wxClientDC dc(this); 
    std::cout<<"paint now() "<<std::endl; 
    render_rt(dc); 
} 

void BasicGLPane::render_rt(wxDC &dc) { 
    wxGLCanvas::SetCurrent(*m_context); 
    if(_object->getCounter()>=10) { 
     wxGetApp().activateRenderLoop(false); 
     manager->stop(); 
     render_on = false; 
    } 
    else { 
     ctx = CGLGetCurrentContext(); //OSx only 
     err = CGLEnable(ctx, kCGLCEMPEngine); //OSX only 
     std::cout<<"render_rt CGLError: "<<err<<std::endl; 
     if (err==0) { 
      glTranslatef(p3->x, p3->y, 0); 
      Refresh(false); 
     } 

    } 
} 

synchronsazion теперь работает.

 Смежные вопросы

  • Нет связанных вопросов^_^