//----------------------------------------------------------------------------- // name: Listener.cpp //----------------------------------------------------------------------------- #include #include #include #include #include #include //#include #ifdef __APPLE__ #include #else #include #endif #include #include "listener.h" #include "RtAudio.h" #include "ticktimer.h" #include "textfile.h" #include #include #include #include "osc/OscReceivedElements.h" #include "osc/OscPrintReceivedElements.h" #include "ip/UdpSocket.h" #include "ip/PacketListener.h" using namespace std; // some defines #define PORT 7000 #define SAMPLE double #define PI 3.14159265358979 #define TARGET_FPS 90 #define SAMPLE_RATE 44100 #define FORMAT RTAUDIO_FLOAT64 #define BASE_RATE 0.005 #define CHANNELS 2 class MyPacketListener : public PacketListener{ public: MyPacketListener(Listener* visual) { _visual = visual; } virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { char endpoint_str[IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH]; remoteEndpoint.AddressAndPortAsString(endpoint_str); //std::cout << endpoint_str << std::endl << osc::ReceivedPacket( data, size ); osc::ReceivedMessage message(osc::ReceivedPacket(data, size)); const char* path = message.AddressPattern(); if (strcmp(path, "/audio_start") == 0) { cout << "start" << endl; _visual->_cur_audio_loop = new AudioLoop; } else if (strcmp(path, "/audio_end") == 0) { if (_visual->_cur_audio_loop->_audio_vector.size() > 512) { _visual->_audio_loops.push_back(_visual->_cur_audio_loop); } else { delete _visual->_cur_audio_loop; _visual->_cur_audio_loop = NULL; } cout << "num loops is " << _visual->_audio_loops.size() << endl; } else if (strcmp(path, "/audio") == 0) { //cout << "end" << endl; assert(message.ArgumentsBegin()->TypeTag() == osc::BLOB_TYPE_TAG); unsigned long blob_size; const SAMPLE* samples; message.ArgumentsBegin()->AsBlobUnchecked((const void*&)samples, blob_size); _visual->_cur_audio_loop->add_samples(samples, blob_size / sizeof(SAMPLE)); //for(unsigned long i = 0; i < blob_size/sizeof(SAMPLE); i++) { // _visual->_audio_buffer[i] = samples[i]; //} } } private: Listener* _visual; bool _receiving_stream; }; void *osc_listen_loop(void *arg){ int port = PORT; MyPacketListener listener((Listener*) arg); UdpListeningReceiveSocket s( IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), &listener ); std::cout << "listening for input on port " << port << "...\n"; std::cout << "press ctrl-c to end\n"; s.RunUntilSigInt(); std::cout << "finishing.\n"; pthread_exit(0); } // audio callback int Listener::audio_callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void* user_data) { /* hack to get this instance from inside static callback */ Listener * self = (Listener *) user_data; SAMPLE * obuffy = (SAMPLE *)outputBuffer; for( unsigned int i = 0; i < nBufferFrames; i++ ) { double sample = 0; for (unsigned j = 0; j < self->_audio_loops.size(); j++) { sample += self->_audio_loops[j]->get_sample(); } obuffy[2*i] = sample; obuffy[2*i+1] = sample; } return 0; } // entry point Listener::Listener() { _window_width = 900; _window_height = 600; _selected_loop = NULL; _is_mouse_pressed = false; init_sdl(); init_gl(); _dac = new RtAudio; if ( _dac->getDeviceCount() < 1 ) { std::cout << "No audio devices found!\n"; exit( 1 ); } // Let RtAudio print messages to stderr. _dac->showWarnings( true ); unsigned int offset = 0; _buffer_size = 512; RtAudio::StreamParameters oParams; oParams.deviceId = _dac->getDefaultOutputDevice(); oParams.nChannels = CHANNELS; oParams.firstChannel = offset; try { _dac->openStream( &oParams, NULL, FORMAT, SAMPLE_RATE, &_buffer_size, audio_callback, this, NULL ); _audio_buffer = new SAMPLE[_buffer_size]; memset(_audio_buffer, '\0', sizeof(_audio_buffer)); _dac->startStream(); } catch ( RtError& e ) { e.printMessage(); return; } // let GLUT handle the current thread from here cout << "initialization SUCCESS! buffer size is " << _buffer_size << endl; pthread_create(&_osc_thread,NULL,osc_listen_loop,this); } Listener::~Listener() { delete _dac; } void Listener::clean_up() { try { _dac->stopStream(); } catch ( RtError& e ) { e.printMessage(); } if ( _dac->isStreamOpen() ) _dac->closeStream(); } //#define GET_PROC(x) x = (void)() SDL_GL_GetProcAddress(#x) void Listener::init_gl() { glEnable(GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glEnable(GL_TEXTURE_2D); } /* initialize sdl screen*/ int Listener::init_sdl() { SDL_Surface *screen; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); return(-1); } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); if (!(screen = SDL_SetVideoMode(_window_width, _window_height, 0, SDL_SWSURFACE | SDL_RESIZABLE | SDL_OPENGL))) { fprintf(stderr, "Unable to set video mode: %s\n", SDL_GetError()); return(-1); } SDL_WM_SetCaption("Realtime Listener", NULL); do_gl_projection(); return(0); } void Listener::do_gl_projection() { double aspect = double(_window_width)/_window_height; // set up coordinate space glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho(-aspect, aspect, -1, 1, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } //----------------------------------------------------------------------------- // Name: reshapeFunc( ) // Desc: called when window size changes //----------------------------------------------------------------------------- void Listener::reshapeFunc( const SDL_ResizeEvent & resize_e ) { int w = resize_e.w, h = resize_e.h; // save the new window size _window_width = w; _window_height = h; // map the view port to the client area glViewport( 0, 0, w, h ); SDL_SetVideoMode(_window_width, _window_height, 0, SDL_SWSURFACE | SDL_RESIZABLE | SDL_OPENGL); cout << "resize: " << _window_width << ", " << _window_height << endl; do_gl_projection(); } int Listener::keyboard_event(const SDL_KeyboardEvent & keyboard_e) { int key = keyboard_e.keysym.sym; switch (key) { case SDLK_ESCAPE: case SDLK_q: return SDL_QUIT; case SDLK_BACKSPACE: case SDLK_DELETE: cout << "stuff?" << endl; if(_selected_loop == NULL) break; for (vector::iterator iter = _audio_loops.begin(); iter != _audio_loops.end(); ++iter) { if (*iter == _selected_loop) { _audio_loops.erase(iter); break; } } delete _selected_loop; _selected_loop = NULL; break; case SDLK_UP: case SDLK_a: if (_selected_loop != NULL) _selected_loop->volume *= 1.2; break; case SDLK_DOWN: case SDLK_b: if (_selected_loop != NULL) _selected_loop->volume *= .8; break; } return 0; } void Listener::mouse_down_event(const SDL_MouseButtonEvent & button_e) { if (button_e.button == 4) { //scroll wheel up if (_selected_loop != NULL) _selected_loop->volume *= 1.1; } else if (button_e.button == 5) { //scroll wheel down if (_selected_loop != NULL) _selected_loop->volume *= .9; } if (button_e.button != 1) return; _is_mouse_pressed = true; /* find the closest buffer */ AudioLoop* closest = NULL; double min_sq_dist = -1; double mouse_x, mouse_y; mouse_x = double(button_e.x - (_window_width - _window_height)/2)/_window_height * 2 - 1; mouse_y = 1 - double(button_e.y)/_window_height * 2; for (unsigned i = 0; i < _audio_loops.size(); i++) { double x_dist = mouse_x - _audio_loops[i]->x; double y_dist = mouse_y - _audio_loops[i]->y; double sq_dist = x_dist * x_dist + y_dist * y_dist; if (sq_dist < min_sq_dist || min_sq_dist < 0) { min_sq_dist = sq_dist; closest = _audio_loops[i]; } } _selected_loop = closest; } void Listener::mouse_up_event(const SDL_MouseButtonEvent & button_e) { if (button_e.button != 1) return; _is_mouse_pressed = false; } void Listener::mouse_motion_event(const SDL_MouseMotionEvent & motion_e) { if (_is_mouse_pressed && _selected_loop != NULL) { double mouse_x, mouse_y; mouse_x = double(motion_e.x - (_window_width - _window_height)/2)/_window_height * 2 - 1; mouse_y = 1 - double(motion_e.y)/_window_height * 2; _selected_loop->x = mouse_x; _selected_loop->y = mouse_y; } } //----------------------------------------------------------------------------- // Name: render( ) // Desc: callback function invoked to draw the client area //----------------------------------------------------------------------------- void Listener::render(double tick_time) { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); //draw_phase_loop(); for (unsigned i = 0; i < _audio_loops.size(); i++) { if(_audio_loops[i] == _selected_loop) { glColor4f( 1,0,0, .2); } else { glColor4f( 1,1,1, .1); } _audio_loops[i]->render(); } // glBegin(GL_LINE_STRIP); { // glVertex2f(mouse_x,mouse_y); // glVertex2f(1,1); // glVertex2f(1,-1); // glVertex2f(-1,-1); // glVertex2f(-1,1); // glVertex2f(1,1); // } glEnd(); SDL_GL_SwapBuffers( ); } void Listener::update(double tick_time) { /* empty for now */ } void Listener::draw_phase_loop() { glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glPointSize(2); double size_mult = 2; for (int j = 3; j > 0; j--) { glLineWidth( j ); glBegin( GL_POINTS ); for( unsigned int i = 0; i < _buffer_size/2; i++ ) { glColor4f( 1,1,1, .5); glVertex2f( size_mult * _audio_buffer[i], size_mult * _audio_buffer[i+ _buffer_size/2]); } for( unsigned int i = 0; i < _buffer_size/2; i++ ) { glColor4f( 1,1,1, .5); glVertex2f( size_mult * _audio_buffer[i + _buffer_size/2], size_mult * _audio_buffer[i]); } glEnd(); } for (int j = 3; j > 0; j--) { glLineWidth( j ); glBegin( GL_LINE_STRIP ); for( unsigned int i = 0; i < _buffer_size/2; i++ ) { glColor4f( 1,1,1, .1); glVertex2f( size_mult * _audio_buffer[i], size_mult * _audio_buffer[i+ _buffer_size/2]); } glEnd(); } } int Listener::main_loop() { bool quit = false; SDL_Event event; TickTimer tick_timer; TickTimer fps_tt; while (!quit) { if (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONDOWN: mouse_down_event(event.button); break; case SDL_MOUSEBUTTONUP: mouse_up_event(event.button); break; case SDL_MOUSEMOTION: mouse_motion_event(event.motion); break ; // if( event.type == SDL_VIDEORESIZE case SDL_VIDEORESIZE: reshapeFunc(event.resize); break; case SDL_KEYDOWN: //case SDL_KEYUP: if (keyboard_event(event.key) == SDL_QUIT) quit = true; break; case SDL_QUIT: quit = true; break; } } else { fps_tt.tick(); double time_elapsed = tick_timer.tick(); update(time_elapsed); render(time_elapsed); double sleep_time = 1.0/TARGET_FPS - fps_tt.tick(); if (sleep_time > 0) usleep(sleep_time * 1000000); } } clean_up(); return(0); }