/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2009 Wincent Balin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include "pdbox.h" #include "m_pd.h" #include "s_stuff.h" /* Welcome to the PDBox plugin */ PLUGIN_HEADER PLUGIN_IRAM_DECLARE /* Name of the file to open. */ char* filename; /* Running time. */ uint64_t runningtime = 0; /* Variables for Pure Data. */ int sys_verbose; int sys_noloadbang; t_symbol *sys_libdir; t_namelist *sys_openlist; int sys_soundindevlist[MAXAUDIOINDEV]; int sys_chinlist[MAXAUDIOINDEV]; int sys_soundoutdevlist[MAXAUDIOOUTDEV]; int sys_choutlist[MAXAUDIOOUTDEV]; /* References for scheduler variables and functions. */ extern t_time sys_time; extern t_time sys_time_per_dsp_tick; extern void sched_tick(t_time next_sys_time); /* LATER consider making this variable. It's now the LCM of all sample rates we expect to see: 32000, 44100, 48000, 88200, 96000. */ #define TIMEUNITPERSEC (32.*441000.) /* Quit flag. */ bool quit = false; /* Thread IDs. */ unsigned int gui_thread_id; unsigned int time_thread_id; /* Stacks for threads. */ #define STACK_SIZE 16384 uint32_t gui_stack[STACK_SIZE / sizeof(uint32_t)]; uint32_t time_stack[256 / sizeof(uint32_t)]; /* GUI thread */ void gui_thread(void) { /* struct datagram pong; */ /* GUI loop */ while(!quit) { #if 0 /* Send ping to the core. */ SEND_TO_CORE("Ping!"); rb->splash(HZ, "Sent ping."); /* Wait for answer. */ while(!RECEIVE_FROM_CORE(&pong)) rb->yield(); /* If got a pong -- everything allright. */ if(memcmp("Pong!", pong.data, pong.size) == 0) { rb->splash(HZ, "Got pong!"); quit = true; break; } #endif if(rb->button_get(false) == BUTTON_OFF) quit = true; rb->sleep(1); } rb->thread_exit(); } /* Running time thread. */ void time_thread(void) { while(!quit) { /* Add time slice in milliseconds. */ runningtime += (1000 / HZ); rb->sleep(1); } rb->thread_exit(); } /* Plug-in entry point */ enum plugin_status plugin_start(const void* parameter) { PLUGIN_IRAM_INIT(rb) /* Memory pool variables. */ size_t mem_size; void* mem_pool; /* Get the file name; check whether parameter contains no file name. */ filename = (char*) parameter; if(strlen(filename) == 0) { rb->splash(HZ, "Play a .pd file!"); return PLUGIN_ERROR; } /* Allocate memory; check it's size; add to the pool. */ mem_pool = rb->plugin_get_audio_buffer(&mem_size); if(mem_size < MIN_MEM_SIZE) { rb->splash(HZ, "Not enough memory!"); return PLUGIN_ERROR; } add_pool(mem_pool, mem_size); /* Initialize net. */ net_init(); /* Initialize Pure Data, as does sys_main in s_main.c */ pd_init(); /* Set audio API. */ sys_set_audio_api(API_ROCKBOX); /* Initialize audio subsystem. */ sys_open_audio(0, /* No sound input yet */ sys_soundindevlist, 0, /* No sound input yet */ sys_chinlist, 1, /* One sound output device */ sys_soundoutdevlist, -1, /* Use the default amount (2) of channels */ sys_choutlist, PD_SAMPLERATE, /* Sample rate */ DEFAULTADVANCE, /* Scheduler advance */ 1 /* Enable */); /* Add the directory the called .pd resides in to lib directories. */ sys_findlibdir(filename); /* Open the parameter file. */ sys_openlist = namelist_append(sys_openlist, filename); /* Fake a GUI start. */ sys_startgui(NULL); /* Start threads. */ time_thread_id = rb->create_thread(&time_thread, time_stack, sizeof(time_stack), 0, /* FIXME Which flags? */ "PD running time" IF_PRIO(, PRIORITY_REALTIME) IF_COP(, COP)); gui_thread_id = rb->create_thread(&gui_thread, gui_stack, sizeof(gui_stack), 0, /* FIXME Which flags? */ "PD GUI" IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); /* If having an error creating threads, bail out. */ if(time_thread_id == 0 || gui_thread_id == 0) return PLUGIN_ERROR; /* Initialize scheduler time variables. */ sys_time = 0; sys_time_per_dsp_tick = (TIMEUNITPERSEC) * ((double) sys_schedblocksize) / sys_dacsr; /* Main loop. */ while(!quit) { /* Use sys_send_dacs() function as timer. */ while(sys_send_dacs() != SENDDACS_NO) sched_tick(sys_time + sys_time_per_dsp_tick); /* Sleep to the next time slice. */ rb->sleep(1); } /* Wait for threads to complete. */ rb->thread_wait(gui_thread_id); rb->thread_wait(time_thread_id); /* Close audio subsystem. */ sys_close_audio(); /* Destroy net. */ net_destroy(); return PLUGIN_OK; }