diff --git a/apps/bees/src/app_bees.c b/apps/bees/src/app_bees.c index ce81a7309..013728718 100644 --- a/apps/bees/src/app_bees.c +++ b/apps/bees/src/app_bees.c @@ -130,7 +130,7 @@ u8 app_launch(eLaunchState state) { render_boot("waiting for DSP init..."); bfin_wait_ready(); - // print_dbg("\r\n enable DSP audio..."); + print_dbg("\r\n enable DSP audio..."); render_boot("enabling audio"); bfin_enable(); diff --git a/apps/bees/src/files.c b/apps/bees/src/files.c index ca1f4068b..810d23e52 100644 --- a/apps/bees/src/files.c +++ b/apps/bees/src/files.c @@ -43,6 +43,7 @@ #define DSP_PATH "/mod/" #define SCENES_PATH "/data/bees/scenes/" #define SCALERS_PATH "/data/bees/scalers/" +#define SAMPLES_PATH "/data/bees/samples/" // endinanness // #define SCALER_LE 1 @@ -66,6 +67,7 @@ typedef struct _dirList { static dirList_t dspList; static dirList_t sceneList; static dirList_t scalerList; +static dirList_t sampleList; //---------------------------------- //---- static functions @@ -77,6 +79,8 @@ static const char* list_get_name(dirList_t* list, u8 idx); // get read file pointer if found (caller must close) // set size by pointer static void* list_open_file_name(dirList_t* list, const char* name, const char* mode, u32* size); +// load sample file with path +static u32 load_sample_withPath(const char *path, u32 offset); // fake fread: no size arg, always byte @@ -159,6 +163,7 @@ void files_init(void) { list_fill(&dspList, DSP_PATH, ".ldr"); list_fill(&sceneList, SCENES_PATH, ".scn"); list_fill(&scalerList, SCALERS_PATH, ".dat"); + list_fill(&sampleList, SAMPLES_PATH, ".pcm_s32be"); } @@ -432,6 +437,46 @@ u8 files_load_scaler_name(const char* name, s32* dst, u32 dstSize) { return ret; } +//////////////////////// +//// samples + +// return filename for sample given index in list +const volatile char* files_get_sample_name(u8 idx) { + return list_get_name(&sampleList, idx); +} + +// return count of sample files +u8 files_get_sample_count(void) { + return sampleList.num; +} + +void files_load_samples(void) { + FL_DIR dirstat; + struct fs_dir_ent dirent; + sampleList.num = 0; + u32 offset = 0; + + char *fpath = (char*)alloc_mem(64 * (sizeof(char*))); + + // check directory for samples + strcpy(sampleList.path, SAMPLES_PATH); + + if (fl_opendir(sampleList.path, &dirstat)) + { + while (fl_readdir(&dirstat, &dirent) == 0) + { + if(!(dirent.is_dir)) + { + strcpy(fpath, sampleList.path); + strcat(fpath, dirent.filename); + offset += load_sample_withPath(fpath, offset); + sampleList.num++; + } + } + } + + free(fpath); +} //--------------------- //------ static @@ -695,3 +740,70 @@ void files_load_sample(u8 n) { } } +static u32 load_sample_withPath(const char *path, u32 offset) { + void *fp; + + u32 fsize, foffset, fchunk, ssize; + + delay_ms(10); + + fp = fl_fopen(path, "r"); + fsize = ((FL_FILE*)(fp))->filelength; + foffset = ((FL_FILE*)(fp))->bytenum % FAT_SECTOR_SIZE; + + ssize = fsize / sizeof(s32); + + // verify available SDRAM + if ((offset + ssize) < BFIN_SDRAM_MAX_FRACT32) + { + if (fp != NULL) + { + render_boot(path); + + app_pause(); + + bfin_sample_start(offset); + + do + { + if (fsize < FAT_SECTOR_SIZE) + { + fchunk = fsize; + } + else + { + fchunk = FAT_SECTOR_SIZE; + } + fsize -= fchunk; + + bfin_sample_transfer(fl_return_sector(fp, foffset), fchunk); + + foffset += 1; + ((FL_FILE*)(fp))->bytenum += fchunk; + } + while (fsize > 0); + + bfin_sample_end(); + + fl_fclose(fp); + + app_resume(); + + return ssize; + } + else + { + render_boot("sample file error"); + fl_fclose(fp); + + return 0; + } + } + else + { + render_boot("SDRAM limit error"); + fl_fclose(fp); + + return 0; + } +} diff --git a/apps/bees/src/files.h b/apps/bees/src/files.h index 3cacfe630..bf6680cbe 100644 --- a/apps/bees/src/files.h +++ b/apps/bees/src/files.h @@ -3,6 +3,7 @@ #include "types.h" #include "util.h" +#include "filesystem.h" //includes fat_filelib.h EXTERN_C_BEGIN // initialize filesystem navigation @@ -63,6 +64,11 @@ extern u8 files_get_scaler_count(void); // return 1 on success, 0 on failure extern u8 files_load_scaler_name(const char* name, s32* dst, u32 dstSize); +//----- samples +extern const volatile char* files_get_sample_name(u8 idx); +extern u8 files_get_sample_count(void); +extern void files_load_samples(void); + //----- param descriptors // search for named .dsc file and load into network param desc memory extern u8 files_load_desc(const char* name); diff --git a/apps/bees/src/pages.c b/apps/bees/src/pages.c index d35989647..1a5915e0b 100644 --- a/apps/bees/src/pages.c +++ b/apps/bees/src/pages.c @@ -61,6 +61,10 @@ page_t pages[NUM_PAGES] = { .select_fn = &select_dsp, // select function .encSens = { ENC_THRESH_LISTSCROLL, ENC_THRESH_PAGESCROLL, 0, 0, }, // encoder sens }, + { .name = "SAMPLES", + .select_fn = &select_samples, // select function + .encSens = { ENC_THRESH_LISTSCROLL, ENC_THRESH_PAGESCROLL, 8, 8, }, // encoder sens + }, // modal: { .name = "GATHERED", .select_fn = &select_gathered , // select function @@ -116,6 +120,7 @@ static u8 check_edit_char(char c) { void pages_init(void) { init_page_ins(); init_page_dsp(); + init_page_samples(); init_page_ops(); init_page_outs(); init_page_play(); @@ -131,6 +136,7 @@ void pages_init(void) { set_page(pageIdx); redraw_dsp(); + redraw_samples(); redraw_outs(); redraw_ops(); redraw_presets(); diff --git a/apps/bees/src/pages.h b/apps/bees/src/pages.h index 6eb2a63b9..19ad45b46 100644 --- a/apps/bees/src/pages.h +++ b/apps/bees/src/pages.h @@ -14,7 +14,7 @@ //-- define //! number of pages (including modal pages) -#define NUM_PAGES 8 +#define NUM_PAGES 9 //! enum of key handlers per menu page typedef enum { @@ -37,6 +37,7 @@ typedef enum { ePageOps, ePageScenes, ePageDsp, + ePageSamples, ePageGathered, ePagePlay, } ePage; @@ -90,6 +91,7 @@ extern void init_page_presets(void); extern void init_page_ops(void); extern void init_page_scenes(void); extern void init_page_dsp(void); +extern void init_page_samples(void); extern void init_page_gathered(void); extern void init_page_play(void); @@ -100,6 +102,7 @@ extern void select_presets(void); extern void select_ops(void); extern void select_scenes(void); extern void select_dsp(void); +extern void select_samples(void); extern void select_gathered(void); extern void select_play(void); @@ -111,6 +114,7 @@ extern void redraw_presets(void); extern void redraw_ops(void); extern void redraw_scenes(void); extern void redraw_dsp(void); +extern void redraw_samples(void); extern void redraw_gathered(void); extern void redraw_play(void); diff --git a/apps/bees/src/pages/page_dsp.c b/apps/bees/src/pages/page_dsp.c index 2333831d5..63d6dc340 100644 --- a/apps/bees/src/pages/page_dsp.c +++ b/apps/bees/src/pages/page_dsp.c @@ -209,7 +209,7 @@ void handle_enc_2(s32 val) { void handle_enc_1(s32 val) { // scroll page if(val > 0) { - set_page(ePageOps); + set_page(ePageSamples); } else { set_page(ePageScenes); } diff --git a/apps/bees/src/pages/page_ops.c b/apps/bees/src/pages/page_ops.c index 02839dad8..5422a3ad0 100644 --- a/apps/bees/src/pages/page_ops.c +++ b/apps/bees/src/pages/page_ops.c @@ -306,7 +306,7 @@ void handle_enc_1(s32 val) { if(val > 0) { set_page(ePageIns); } else { - set_page(ePageDsp); + set_page(ePageSamples); } } diff --git a/apps/bees/src/pages/page_samples.c b/apps/bees/src/pages/page_samples.c new file mode 100644 index 000000000..f3e9ef2e7 --- /dev/null +++ b/apps/bees/src/pages/page_samples.c @@ -0,0 +1,288 @@ +/* + page_samples.c +*/ + +// asf +#include "print_funcs.h" + +// aleph-avr32 +#include "bfin.h" + +// bees +#include "files.h" +#include "handler.h" +#include "net.h" +#include "pages.h" +#include "render.h" +#include "scene.h" + +//------------------------- +//---- static variables + + +// constant pointer to this page's selection +static s16* const pageSelect = &(pages[ePageSamples].select); + +// scroll region +static region scrollRegion = { .w = 128, .h = 64, .x = 0, .y = 0 }; +// scroll manager +static scroll centerScroll; + +// handler declarations +static void handle_enc_3(s32 val); +static void handle_enc_2(s32 val); +static void handle_enc_1(s32 val); +static void handle_enc_0(s32 val); +static void handle_key_0(s32 val); +static void handle_key_1(s32 val); +static void handle_key_2(s32 val); +static void handle_key_3(s32 val); + +// fill tmp region with new content +// given input index +static void render_line(s16 idx, u16 max) { + region_fill(lineRegion, 0x0); + if((idx > max) || (idx < 0)) { return; } + clearln(); + appendln((const char*)files_get_sample_name(idx)); + endln(); + font_string_region_clip(lineRegion, lineBuf, 0, 0, 0xa, 0); +} + + +// scroll the current selection +static void select_scroll(s32 dir) { + const s32 max = files_get_sample_count() - 1; + // index for new content + s16 newIdx; + s16 newSel; + + // cancel actions + pages_reset_keypressed(); + + if(dir < 0) { + /// SCROLL DOWN + // if selection is already zero, do nothing + if(*pageSelect == 0) { + // print_dbg("\r\n reached min selection in inputs scroll. "); + return; + } + // remove highlight from old center + render_scroll_apply_hl(SCROLL_CENTER_LINE, 0); + // decrement selection + newSel = *pageSelect - 1; + ///// these bounds checks shouldn't really be needed here... + // if(newSel < 0) { newSel = 0; } + // if(newSel > max ) { newSel = max; } + *pageSelect = newSel; + // add new content at top + newIdx = newSel - SCROLL_LINES_BELOW; + if(newIdx < 0) { + // empty row + region_fill(lineRegion, 0); + } else { + render_line(newIdx, max); + } + // render tmp region to bottom of scroll + // (this also updates scroll byte offset) + render_to_scroll_top(); + // add highlight to new center + render_scroll_apply_hl(SCROLL_CENTER_LINE, 1); + + } else { + // SCROLL UP + // if selection is already max, do nothing + if(*pageSelect == max) { + // print_dbg("\r\n reached max selection in inputs scroll. "); + return; + } + // remove highlight from old center + render_scroll_apply_hl(SCROLL_CENTER_LINE, 0); + // increment selection + newSel = *pageSelect + 1; + ///// these bounds checks shouldn't really be needed here... + // if(newSel < 0) { newSel = 0; } + // if(newSel > max ) { newSel = max; } + ///// + *pageSelect = newSel; + // add new content at bottom of screen + newIdx = newSel + SCROLL_LINES_ABOVE; + if(newIdx > max) { + // empty row + region_fill(lineRegion, 0); + } else { + render_line(newIdx, max); + } + // render tmp region to bottom of scroll + // (this also updates scroll byte offset) + render_to_scroll_bottom(); + // add highlight to new center + render_scroll_apply_hl(SCROLL_CENTER_LINE, 1); + } +} + +// display the function key labels according to current state +static void show_foot0(void) { + u8 fill = 0; + if(keyPressed == 0) { + fill = 0x5; + } + region_fill(footRegion[0], fill); + font_string_region_clip(footRegion[0], "LOAD", 0, 0, 0xf, fill); +} + +#if BFIN_INTERNAL_FLASH +static void show_foot1(void) { +u8 fill = 0; +if(keyPressed == 1) { +fill = 0x5; +} +region_fill(footRegion[1], fill); +font_string_region_clip(footRegion[1], "WRITE", 0, 0, 0xf, fill); + +} +#endif + +static void show_foot(void) { +show_foot0(); +#if BFIN_INTERNAL_FLASH +show_foot1(); +#endif +} + +// function keys +void handle_key_0(s32 val) { + // load module + if(val == 0) { return; } + if(check_key(0)) { + notify("loading samples..."); + + net_disconnect_params(); + + bfin_wait_ready(); + bfin_disable(); + + files_load_samples(); + + bfin_wait_ready(); + bfin_enable(); + + redraw_ins(); + redraw_samples(); + + notify("finished loading."); + } + show_foot(); +} + +void handle_key_1(s32 val) { +#if BFIN_INTERNAL_FLASH + + if(val == 0) { return; } + if(check_key(1)) { + notify("writing..."); + files_store_default_dsp(*pageSelect); + notify("done writing."); + } + show_foot(); + +#endif +} + +void handle_key_2(s32 val) { + // nothing +} + +void handle_key_3(s32 val) { + // nothing +} + +// enc 0 : scroll page +void handle_enc_3(s32 val) { + // nothing +} + +// enc 1 : scroll selection +void handle_enc_2(s32 val) { + // nothing +} + +void handle_enc_1(s32 val) { + // scroll page + if(val > 0) { + set_page(ePageOps); + } else { + set_page(ePageDsp); + } +} + +void handle_enc_0(s32 val) { + select_scroll(val); +} + +//---------------------- +// ---- extern +// init +void init_page_samples(void) { + u8 i, n; + u16 max = files_get_sample_count() - 1; + print_dbg("\r\n alloc SAMPLES page"); + // allocate regions + region_alloc(&scrollRegion); + // init scroll + scroll_init(¢erScroll, &scrollRegion); + // fill regions + region_fill(&scrollRegion, 0x0); + // fill the scroll with actual line values... + n = 3; + i = 0; + //// need to actually set the scroll region at least temporarily + render_set_scroll(¢erScroll); + // also, reset scroller! + while(i<5) { + render_line(i, max); + render_to_scroll_line(n, i == 0 ? 1 : 0); + ++n; + ++i; + } +} + +// select +void select_samples(void) { + // assign global scroll region pointer + // also marks dirty + render_set_scroll(¢erScroll); + // other regions are static in top-level render, with global handles + render_reset_custom_region(); + region_fill(headRegion, 0x0); + font_string_region_clip(headRegion, "SAMPLES", 0, 0, 0xf, 0x1); + show_foot(); + // assign handlers + app_event_handlers[ kEventEncoder0 ] = &handle_enc_0 ; + app_event_handlers[ kEventEncoder1 ] = &handle_enc_1 ; + app_event_handlers[ kEventEncoder2 ] = &handle_enc_2 ; + app_event_handlers[ kEventEncoder3 ] = &handle_enc_3 ; + app_event_handlers[ kEventSwitch0 ] = &handle_key_0 ; + app_event_handlers[ kEventSwitch1 ] = &handle_key_1 ; + app_event_handlers[ kEventSwitch2 ] = &handle_key_2 ; + app_event_handlers[ kEventSwitch3 ] = &handle_key_3 ; +} + +// redraw all lines, based on current selection +void redraw_samples(void) { + u8 i=0; + u8 n = *pageSelect - 3; + + // set scroll region + // FIXME: should be separate function i guess + render_set_scroll(¢erScroll); + + + print_dbg("\r\n redraw_samples() "); + while(i<8) { + render_line( n, 0xa ); + render_to_scroll_line(i, n == *pageSelect ? 1 : 0); + ++i; + ++n; + } +} diff --git a/avr32/src/bfin.c b/avr32/src/bfin.c index 476bb04ae..86647f731 100644 --- a/avr32/src/bfin.c +++ b/avr32/src/bfin.c @@ -210,6 +210,41 @@ void bfin_get_module_version(ModuleVersion* vers) { app_resume(); } +void bfin_sample_start(s32 offset) { + ParamValueSwap o; + + // send offset + o.asInt = offset; + + bfin_wait(); + spi_selectChip(BFIN_SPI, BFIN_SPI_NPCS); + + // set command + spi_write(BFIN_SPI, MSG_OFFSET_COM); + while (!(BFIN_SPI->sr & AVR32_SPI_SR_TXEMPTY_MASK)) { ;; }; + + // byte 1 + spi_write(BFIN_SPI, o.asByte[0]); + while (!(BFIN_SPI->sr & AVR32_SPI_SR_TXEMPTY_MASK)) { ;; }; + + // byte 2 + spi_write(BFIN_SPI, o.asByte[1]); + while (!(BFIN_SPI->sr & AVR32_SPI_SR_TXEMPTY_MASK)) { ;; }; + + // byte 3 + spi_write(BFIN_SPI, o.asByte[2]); + while (!(BFIN_SPI->sr & AVR32_SPI_SR_TXEMPTY_MASK)) { ;; }; + + // byte 4 + spi_write(BFIN_SPI, o.asByte[3]); + while (!(BFIN_SPI->sr & AVR32_SPI_SR_TXEMPTY_MASK)) { ;; }; +} + +void bfin_sample_end(void) { + bfin_wait(); + spi_unselectChip(BFIN_SPI, BFIN_SPI_NPCS); +} + void bfin_enable(void) { // enable audio processing spi_selectChip(BFIN_SPI, BFIN_SPI_NPCS); diff --git a/avr32/src/bfin.h b/avr32/src/bfin.h index 56fd1d88f..e5735f796 100644 --- a/avr32/src/bfin.h +++ b/avr32/src/bfin.h @@ -14,6 +14,7 @@ //! max size of blackfin ldr file #define BFIN_LDR_MAX_BYTES 0x12000 +#define BFIN_SDRAM_MAX_FRACT32 0x1000000 //! wait for busy pin to clear void bfin_wait(void); @@ -36,6 +37,12 @@ void bfin_get_module_name(volatile char* buf); //! get loaded module version void bfin_get_module_version(ModuleVersion* vers); +//! start sample transfer +extern void bfin_sample_start(s32 offset); + +//! end sample transfer +extern void bfin_sample_end(void); + //! enable audio processing extern void bfin_enable(void); diff --git a/avr32/src/fat_io_lib/fat_filelib.c b/avr32/src/fat_io_lib/fat_filelib.c index e6f9142f9..698871ac1 100644 --- a/avr32/src/fat_io_lib/fat_filelib.c +++ b/avr32/src/fat_io_lib/fat_filelib.c @@ -605,6 +605,75 @@ static uint32 _read_sectors(FL_FILE *file, uint32 offset, uint8 *buffer, // External API //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// fl_return_sector: Return current file offset +//----------------------------------------------------------------------------- + +uint32 fl_return_sector(FL_FILE *file, uint32 offset) +{ + uint32 Sector = 0; + uint32 ClusterIdx = 0; + uint32 Cluster = 0; + uint32 i; + + // Find cluster index within file & sector with cluster + ClusterIdx = offset / _fs.sectors_per_cluster; + Sector = offset - (ClusterIdx * _fs.sectors_per_cluster); + + // Quick lookup for next link in the chain + if (ClusterIdx == file->last_fat_lookup.ClusterIdx) + Cluster = file->last_fat_lookup.CurrentCluster; + // Else walk the chain + else + { + // Starting from last recorded cluster? + if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1) + { + i = file->last_fat_lookup.ClusterIdx; + Cluster = file->last_fat_lookup.CurrentCluster; + } + // Start searching from the beginning.. + else + { + // Set start of cluster chain to initial value + i = 0; + Cluster = file->startcluster; + } + + // Follow chain to find cluster to read + for ( ;ilast_fat_lookup.CurrentCluster = Cluster; + file->last_fat_lookup.ClusterIdx = ClusterIdx; + } + } + + // If end of cluster chain then return false + if (Cluster == FAT32_LAST_CLUSTER) + return 0; + + // Calculate sector address + return fatfs_lba_of_cluster(&_fs, Cluster) + Sector; +} + //----------------------------------------------------------------------------- // fl_init: Initialise library //----------------------------------------------------------------------------- diff --git a/avr32/src/fat_io_lib/fat_filelib.h b/avr32/src/fat_io_lib/fat_filelib.h index d3da92b60..fa8dc4763 100644 --- a/avr32/src/fat_io_lib/fat_filelib.h +++ b/avr32/src/fat_io_lib/fat_filelib.h @@ -81,6 +81,7 @@ int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr); void fl_shutdown(void); // Standard API +uint32 fl_return_sector(FL_FILE *file, uint32 offset); void *fl_fopen(const char *path, const char *modifiers); void fl_fclose(void *file); int fl_fflush(void *file); diff --git a/avr32/src/filesystem.c b/avr32/src/filesystem.c index 577436b43..da900245c 100644 --- a/avr32/src/filesystem.c +++ b/avr32/src/filesystem.c @@ -34,8 +34,6 @@ volatile avr32_pdca_channel_t *pdcaTxChan; //---- low level i/o int media_read(unsigned long sector, unsigned char *buffer, unsigned long sector_count); - -// PRGM SAMPLE TRANSFER PR, REMOVED FLAG! int media_read(unsigned long sector, unsigned char *buffer, unsigned long sector_count) { unsigned long i; @@ -126,7 +124,6 @@ int fat_init(void) { } } -//PRGM SAMPLE TRANSFER PR; THIS COULD MAYBE LIVE SOMEWHER ELSE.. int bfin_sample_transfer(unsigned long sector, unsigned long bytes) { unsigned long i; diff --git a/avr32/src/filesystem.h b/avr32/src/filesystem.h index c592e0d4a..f39dc3ba1 100644 --- a/avr32/src/filesystem.h +++ b/avr32/src/filesystem.h @@ -8,8 +8,6 @@ //===================================== //==== vars -// transfer-done flag -//extern volatile u8 fsEndTransfer; // Local RAM buffer to store data to/from the SD/MMC card extern volatile U8 pdcaRxBuf[FS_BUF_SIZE]; extern volatile U8 pdcaTxBuf[FS_BUF_SIZE]; @@ -20,8 +18,6 @@ extern volatile avr32_pdca_channel_t* pdcaTxChan; //==================================== //==== funcs extern int fat_init(void); - -//PRGM SAMPLE TRANSFER PR extern int bfin_sample_transfer(unsigned long sector, unsigned long bytes); #endif // h guard diff --git a/avr32/src/init.c b/avr32/src/init.c index f3adf563c..8cd223765 100644 --- a/avr32/src/init.c +++ b/avr32/src/init.c @@ -256,7 +256,7 @@ void init_bfin_resources(void) { .spck_delay = 0, // .trans_delay = 0, //// try and reduce this... - .trans_delay = 20, + .trans_delay = 1, .stay_act = 1, .spi_mode = 1, .modfdis = 1 diff --git a/avr32/src/interrupts.c b/avr32/src/interrupts.c index a03a0c3f3..06c54cd16 100644 --- a/avr32/src/interrupts.c +++ b/avr32/src/interrupts.c @@ -84,8 +84,6 @@ static void irq_pdca(void) { // enable all interrupts. cpu_irq_enable(); - - //REMOVED FLAG, SEE filesystem.c } // timer irq diff --git a/bfin_lib/src/module.h b/bfin_lib/src/module.h index 40a17b52c..0894fd90a 100644 --- a/bfin_lib/src/module.h +++ b/bfin_lib/src/module.h @@ -61,6 +61,10 @@ extern void module_init(void); extern void module_deinit(void); // callback extern void module_process_frame(void); +// sample offset +extern void module_set_offset(s32 offset); +// sample +extern void module_set_sample(s32 sample); // set parameter extern void module_set_param(u32 idx, ParamValue val); diff --git a/bfin_lib/src/spi.c b/bfin_lib/src/spi.c index cf54f9732..c3e2c2bb1 100644 --- a/bfin_lib/src/spi.c +++ b/bfin_lib/src/spi.c @@ -31,6 +31,9 @@ static void spi_set_param(u32 idx, ParamValue pv) { // return byte to load for next MISO u8 spi_process(u8 rx) { static ParamValueSwap pval; + static ParamValueSwap o; + static ParamValueSwap s; + switch(byte) { /// caveman style case statement case eCom : @@ -62,14 +65,12 @@ u8 spi_process(u8 rx) { processAudio = 0; return processAudio; break; - - case MSG_OFFSET_COM : - byte = eOffset0; - break; - - case MSG_SAMPLE_COM : - byte = eSample0; - break; + case MSG_OFFSET_COM: + byte = eOffset0; + break; + case MSG_SAMPLE_COM: + byte = eSample0; + break; default: break; @@ -268,53 +269,48 @@ u8 spi_process(u8 rx) { return 0; // don't care break; - - // set offset - case eOffset0 : - byte = eOffset1; - o.asByte[3] = rx; - return 0; - break; - case eOffset1 : - byte = eOffset2; - o.asByte[2] = rx; - return 0; - break; - case eOffset2 : - byte = eOffset3; - o.asByte[1] = rx; - return 0; - break; - case eOffset3 : - o.asByte[0] = rx; - module_set_offset(o.asInt); - byte = eCom; - return 0; - break; - - // set sample - case eSample0 : - byte = eSample1; - s.asByte[3] = rx; - return 0; - break; - case eSample1 : - byte = eSample2; - s.asByte[2] = rx; - return 0; - break; - case eSample2 : - byte = eSample3; - s.asByte[1] = rx; - return 0; - break; - case eSample3 : - s.asByte[0] = rx; - module_set_sample(s.asInt); - byte = eCom; - return 0; - break; - + case eOffset0 : + byte = eOffset1; + o.asByte[3] = rx; + return 0; + break; + case eOffset1 : + byte = eOffset2; + o.asByte[2] = rx; + return 0; + break; + case eOffset2 : + byte = eOffset3; + o.asByte[1] = rx; + return 0; + break; + case eOffset3 : + o.asByte[0] = rx; + module_set_offset(o.asInt); + byte = eCom; + return 0; + break; + case eSample0 : + byte = eSample1; + s.asByte[3] = rx; + return 0; + break; + case eSample1 : + byte = eSample2; + s.asByte[2] = rx; + return 0; + break; + case eSample2 : + byte = eSample3; + s.asByte[1] = rx; + return 0; + break; + case eSample3 : + s.asByte[0] = rx; + module_set_sample(s.asInt); + byte = eCom; + return 0; + break; default: byte = eCom; // reset diff --git a/common/protocol.h b/common/protocol.h index 98a5d4137..97b538be7 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -32,9 +32,9 @@ // get param change CPU use (0 - 0x7fffffff) #define MSG_GET_CONTROL_CPU_COM 10 -// PRGM SAMPLE TRANSFER, THESE WOULD BE ADDED WITH APPROPRIATE ID's! -#define MSG_OFFSET_COM X -#define MSG_SAMPLE_COM Y +// sample transfer commands +#define MSG_OFFSET_COM 11 +#define MSG_SAMPLE_COM 12 // enumerate state-machine nodes for sending and receiving SPI. @@ -95,6 +95,18 @@ typedef enum { eModuleVersionRev0, eModuleVersionRev1, + // sample offset + eOffset0, + eOffset1, + eOffset2, + eOffset3, + + // sample + eSample0, + eSample1, + eSample2, + eSample3, + // buffer eBufferNumBytes0, eBufferNumBytes1, @@ -112,18 +124,6 @@ typedef enum { eGetControlCpuData1, eGetControlCpuData2, - // offset - eOffset0, - eOffset1, - eOffset2, - eOffset3, - - // sample - eSample0, - eSample1, - eSample2, - eSample3, - eNumSpiBytes } eSpiByte; diff --git a/modules/mix/mix.c b/modules/mix/mix.c index ac71728e8..c97b3e754 100644 --- a/modules/mix/mix.c +++ b/modules/mix/mix.c @@ -12,6 +12,10 @@ */ +//-- blackfin toolchain headers +// 1.32 and 1.15 fixed-point arithmeti +#include "fract_math.h" + //-- aleph/common headers #include "types.h" @@ -22,7 +26,6 @@ #include "cv.h" // gpio pin numbers #include "gpio.h" -#include "fract_math.h" //-- dsp class headers // simple 1-pole integrator diff --git a/modules/mix/mix.lds b/modules/mix/mix.lds index 800eb82dc..aa7690c63 100755 --- a/modules/mix/mix.lds +++ b/modules/mix/mix.lds @@ -1,25 +1,255 @@ /* - * Copyright (C) 2007, 2008 Analog Devices, Inc. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. - */ +* Copyright (C) 2007, 2008 Analog Devices, Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice is included verbatim in any distributions. No written agreement, +* license, or royalty fee is required for any of the authorized uses. +* Modifications to this software may be copyrighted by their authors +* and need not follow the licensing terms described here, provided that +* the new terms are clearly indicated on the first page of each file where +* they apply. +*/ /* The default linker script, for single core blackfin standalone executables */ MEMORY { - MEM_L1_CODE : ORIGIN = 0xFFA00000, LENGTH = 0x10000 - MEM_L1_CODE_CACHE : ORIGIN = 0xFFA10000, LENGTH = 0x4000 - MEM_L1_SCRATCH : ORIGIN = 0xFFB00000, LENGTH = 0x1000 - MEM_L1_DATA_B : ORIGIN = 0xFF900000, LENGTH = 0x8000 - MEM_L1_DATA_A : ORIGIN = 0xFF800000, LENGTH = 0x8000 - MEM_L2 : ORIGIN = 0xFEB00000, LENGTH = 0x0 +MEM_L1_CODE : ORIGIN = 0xFFA00000, LENGTH = 0x10000 +MEM_L1_CODE_CACHE : ORIGIN = 0xFFA10000, LENGTH = 0x4000 +MEM_L1_SCRATCH : ORIGIN = 0xFFB00000, LENGTH = 0x1000 +MEM_L1_DATA_B : ORIGIN = 0xFF900000, LENGTH = 0x8000 +MEM_L1_DATA_A : ORIGIN = 0xFF800000, LENGTH = 0x8000 +MEM_L2 : ORIGIN = 0xFEB00000, LENGTH = 0x0 +} + +OUTPUT_FORMAT("elf32-bfin", "elf32-bfin", +"elf32-bfin") +OUTPUT_ARCH(bfin) +ENTRY(__start) + +SECTIONS +{ +/* Read-only sections, merged into text segment: */ +PROVIDE (__executable_start = 0x0); . = 0x0; +.interp : { *(.interp) } +.hash : { *(.hash) } +.dynsym : { *(.dynsym) } +.dynstr : { *(.dynstr) } +.gnu.version : { *(.gnu.version) } +.gnu.version_d : { *(.gnu.version_d) } +.gnu.version_r : { *(.gnu.version_r) } +.rel.init : { *(.rel.init) } +.rela.init : { *(.rela.init) } +.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } +.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } +.rel.fini : { *(.rel.fini) } +.rela.fini : { *(.rela.fini) } +.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } +.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } +.rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } +.rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } +.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } +.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } +.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } +.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } +.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } +.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } +.rel.ctors : { *(.rel.ctors) } +.rela.ctors : { *(.rela.ctors) } +.rel.dtors : { *(.rel.dtors) } +.rela.dtors : { *(.rela.dtors) } +.rel.got : { *(.rel.got) } +.rela.got : { *(.rela.got) } +.rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } +.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } +.rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } +.rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } +.rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } +.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } +.rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } +.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } +.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } +.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } +.rel.plt : { *(.rel.plt) } +.rela.plt : { *(.rela.plt) } + +.l2 : +{ +*(.l2 .l2.*) +} >MEM_L2 =0 + +.text : +{ +*(.text .stub .text.* .gnu.linkonce.t.* .l1.text .l1.text.*) +KEEP (*(.text.*personality*)) +/* .gnu.warning sections are handled specially by elf32.em. */ +*(.gnu.warning) +} >MEM_L1_CODE =0 + +.init : +{ +KEEP (*(.init)) +} >MEM_L1_CODE =0 +.plt : { *(.plt) } >MEM_L1_CODE +.fini : + +{ +KEEP (*(.fini)) +} >MEM_L1_CODE =0 + +PROVIDE (__etext = .); +PROVIDE (_etext = .); +PROVIDE (etext = .); +.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } >MEM_L1_DATA_A +.rodata1 : { *(.rodata1) } >MEM_L1_DATA_A + +.sdata2 : +{ +*(.sdata2 .sdata2.* .gnu.linkonce.s2.*) +} >MEM_L1_DATA_A + +.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } >MEM_L1_DATA_A +.eh_frame_hdr : { *(.eh_frame_hdr) } >MEM_L1_DATA_A +.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } >MEM_L1_DATA_A +.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >MEM_L1_DATA_A +/* Adjust the address for the data segment. We want to adjust up to +the same address within the page on the next page up. */ +. = ALIGN(0x1000) + (. & (0x1000 - 1)); +/* Exception handling */ +.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } >MEM_L1_DATA_A +.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >MEM_L1_DATA_A +/* Thread Local Storage sections */ +.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } >MEM_L1_DATA_A +.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } >MEM_L1_DATA_A +.preinit_array : +{ +PROVIDE_HIDDEN (___preinit_array_start = .); +KEEP (*(.preinit_array)) +PROVIDE_HIDDEN (___preinit_array_end = .); +} >MEM_L1_DATA_A +.init_array : +{ +PROVIDE_HIDDEN (___init_array_start = .); +KEEP (*(SORT(.init_array.*))) +KEEP (*(.init_array)) +PROVIDE_HIDDEN (___init_array_end = .); +} >MEM_L1_DATA_A +.fini_array : +{ +PROVIDE_HIDDEN (___fini_array_start = .); +KEEP (*(.fini_array)) +KEEP (*(SORT(.fini_array.*))) +PROVIDE_HIDDEN (___fini_array_end = .); +} >MEM_L1_DATA_A + +.ctors : +{ +/* gcc uses crtbegin.o to find the start of +the constructors, so we make sure it is +first. Because this is a wildcard, it +doesn't matter if the user does not +actually link against crtbegin.o; the +linker won't look for a file to match a +wildcard. The wildcard also means that it +doesn't matter which directory crtbegin.o +is in. */ +KEEP (*crtbegin*.o(.ctors)) +/* We don't want to include the .ctor section from +the crtend.o file until after the sorted ctors. +The .ctor section from the crtend file contains the +end of ctors marker and it must be last */ +KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) +KEEP (*(SORT(.ctors.*))) +KEEP (*(.ctors)) +} >MEM_L1_DATA_A + +.dtors : +{ +KEEP (*crtbegin*.o(.dtors)) +KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) +KEEP (*(SORT(.dtors.*))) +KEEP (*(.dtors)) +} >MEM_L1_DATA_A + +.jcr : { KEEP (*(.jcr)) } >MEM_L1_DATA_A +.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } >MEM_L1_DATA_A +.dynamic : { *(.dynamic) } >MEM_L1_DATA_A +.data : +{ +*(.data .data.* .gnu.linkonce.d.* .l1.data .l1.data.*) +KEEP (*(.gnu.linkonce.d.*personality*)) +SORT(CONSTRUCTORS) +} >MEM_L1_DATA_A +.data1 : { *(.data1) } >MEM_L1_DATA_A +.got : { *(.got.plt) *(.got) } >MEM_L1_DATA_A +/* We want the small data sections together, so single-instruction offsets +can access them all, and initialized data all before uninitialized, so +we can shorten the on-disk segment size. */ +.sdata : +{ +*(.sdata .sdata.* .gnu.linkonce.s.*) +} >MEM_L1_DATA_A +__edata = .; PROVIDE (_edata = .); +.sbss : +{ +__bss_start = .; +*(.dynsbss) +*(.sbss .sbss.* .gnu.linkonce.sb.*) +*(.scommon) +} >MEM_L1_DATA_A +.bss : +{ +*(.dynbss) +*(.bss .bss.* .gnu.linkonce.b.*) +*(COMMON) +/* Align here to ensure that the .bss section occupies space up to +_end. Align after .bss to ensure correct alignment even if the +.bss section disappears because there are no input sections. +FIXME: Why do we need it? When there is no .bss section, we don't +pad the .data section. */ +. = ALIGN(. != 0 ? 32 / 8 : 1); +__bss_end = .; +} >MEM_L1_DATA_A +. = ALIGN(32 / 8); +. = ALIGN(32 / 8); +__end = .; PROVIDE (_end = .); +/* Stabs debugging sections. */ +.stab 0 : { *(.stab) } +.stabstr 0 : { *(.stabstr) } +.stab.excl 0 : { *(.stab.excl) } +.stab.exclstr 0 : { *(.stab.exclstr) } +.stab.index 0 : { *(.stab.index) } +.stab.indexstr 0 : { *(.stab.indexstr) } +.comment 0 : { *(.comment) } +/* DWARF debug sections. +Symbols in the DWARF debugging sections are relative to the beginning +of the section so we begin them at 0. */ +/* DWARF 1 */ +.debug 0 : { *(.debug) } +.line 0 : { *(.line) } +/* GNU DWARF 1 extensions */ +.debug_srcinfo 0 : { *(.debug_srcinfo) } +.debug_sfnames 0 : { *(.debug_sfnames) } +/* DWARF 1.1 and DWARF 2 */ +.debug_aranges 0 : { *(.debug_aranges) } +.debug_pubnames 0 : { *(.debug_pubnames) } +/* DWARF 2 */ +.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } +.debug_abbrev 0 : { *(.debug_abbrev) } +.debug_line 0 : { *(.debug_line) } +.debug_frame 0 : { *(.debug_frame) } +.debug_str 0 : { *(.debug_str) } +.debug_loc 0 : { *(.debug_loc) } +.debug_macinfo 0 : { *(.debug_macinfo) } +/* SGI/MIPS DWARF 2 extensions */ +.debug_weaknames 0 : { *(.debug_weaknames) } +.debug_funcnames 0 : { *(.debug_funcnames) } +.debug_typenames 0 : { *(.debug_typenames) } +.debug_varnames 0 : { *(.debug_varnames) } + +__stack_end = ORIGIN(MEM_L1_SCRATCH) + LENGTH(MEM_L1_SCRATCH); + +/DISCARD/ : { *(.note.GNU-stack) } } diff --git a/modules/sample/Makefile b/modules/sample/Makefile new file mode 100644 index 000000000..9ced6f521 --- /dev/null +++ b/modules/sample/Makefile @@ -0,0 +1,92 @@ + +# change this to your module name +module_name = sample + +# paths to aleph repository sources +audio = ../../dsp +bfin = ../../bfin_lib/src + +include version.mk +version = $(maj).$(min).$(rev) +ldr_name = $(module_name)-$(version).ldr + +# add sources from here/audio library. +module_obj = sample.o \ + $(audio)/filter_1p.o \ + + +# ----- below here, probably dont need to customize. + +all: $(module_name).ldr + +# this gets the core configuration and sources +include ../../bfin_lib/bfin_lib.mk + +CFLAGS += -D ARCH_BFIN=1 +# diagnose gcc errors +# CFLAGS += --verbose + +desc_src = \ + $(bfin_lib_srcdir)desc.c \ + $(bfin_lib_srcdir)pickle.c \ + params.c + +# this target generates the descriptor helper program +desc: + gcc $(desc_src) \ + $(INC) \ + -D NAME=\"$(module_name)\" \ + -o $(module_name)_desc_build + +$(module_obj): %.o : %.c + $(CC) $(CFLAGS) -c -o $@ $< $(LDFLAGS) + +$(module_name): bfin_lib_target $(module_obj) + $(CC) $(LDFLAGS) -T $(module_name).lds \ + $(patsubst %.o, $(bfin_lib_objdir)%.o, $(bfin_lib_obj)) \ + $(module_obj) \ + -o $(module_name) \ + -lm -lbfdsp -lbffastfp + +clean: bfin_lib_clean + rm $(module_obj) + rm $(module_name).ldr + rm $(module_name) + +# this generates the module and descriptor helper app, +# runs the descrptor app to generate .dsc, +# and makes copies with version number strings. +# best used after "make clean" +deploy: $(module_name).ldr + make desc + ./$(module_name)_desc_build + cp $(module_name).ldr $(module_name)-$(maj).$(min).$(rev).ldr + cp $(module_name).dsc $(module_name)-$(maj).$(min).$(rev).dsc + +.PHONY: clean + deploy + + +sim_sourcefiles = mix.c \ + $(audio)/filter_1p.c \ + params.c \ + ../../utils/bfin_sim/main.c \ + ../../utils/bfin_sim/src/cv.c \ + ../../utils/bfin_sim/fract2float_conv.c \ + ../../utils/bfin_sim/fract_math.c + +sim_inc = -I ../../dsp \ + -I ../../utils/bfin_sim/src \ + -I ../../utils/bfin_sim/ \ + -I ../../utils/bfin_sim/src/libfixmath \ + -I ./ \ + -I ../../common\ + +sim_outfile = mix_jack + +sim_flags = -ljack -llo -D ARCH_LINUX=1 + +sim: + touch $(sim_outfile) + rm ./$(sim_outfile) + gcc $(sim_sourcefiles) $(sim_flags) $(sim_inc) -o $(sim_outfile) -g diff --git a/modules/sample/module_custom.h b/modules/sample/module_custom.h new file mode 100644 index 000000000..827595f34 --- /dev/null +++ b/modules/sample/module_custom.h @@ -0,0 +1,20 @@ +/* module_custom.h + + some consants should be both customized for each module, + and preprocessed for efficiency. + here is where such things live. + + most likely, this is just a count of parameters. + + a copy of this header should exist in your custom modiule directory + (e.g. aleph/bfin/modules/mymodule/ + */ + +#ifndef _ALEPH_MODULE_CUSTOM_H_ +#define _ALEPH_MODULE_CUSTOM_H_ + +#include "params.h" + +#define NUM_PARAMS eParamNumParams + +#endif diff --git a/modules/sample/params.c b/modules/sample/params.c new file mode 100644 index 000000000..e03cb3560 --- /dev/null +++ b/modules/sample/params.c @@ -0,0 +1,133 @@ +/* + params.c + parameter descriptor fields. +*/ + +#include +#include "module.h" +#include "params.h" + +extern void fill_param_desc(ParamDesc* desc) { + + strcpy(desc[eParam0].label, "level 0"); + desc[eParam0].type = eParamTypeAmp; + desc[eParam0].min = 0x00000000; + desc[eParam0].max = PARAM_AMP_MAX; + desc[eParam0].radix = 16; + + strcpy(desc[eParam1].label, "start 0"); + desc[eParam1].type = eParamTypeFix; + desc[eParam1].min = 0x00000000; + desc[eParam1].max = PARAM_SECONDS_MAX; + desc[eParam1].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam2].label, "loop 0"); + desc[eParam2].type = eParamTypeFix; + desc[eParam2].min = 0x00000000; + desc[eParam2].max = PARAM_SECONDS_MAX; + desc[eParam2].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam3].label, "direction 0"); + desc[eParam3].type = eParamTypeBool; + desc[eParam3].min = 0; + desc[eParam3].max = 1; + desc[eParam3].radix = 1; + + strcpy(desc[eParam4].label, "trig 0"); + desc[eParam4].type = eParamTypeBool; + desc[eParam4].min = 0; + desc[eParam4].max = 1; + desc[eParam4].radix = 1; + + strcpy(desc[eParam5].label, "level 1"); + desc[eParam5].type = eParamTypeAmp; + desc[eParam5].min = 0x00000000; + desc[eParam5].max = PARAM_AMP_MAX; + desc[eParam5].radix = 16; + + strcpy(desc[eParam6].label, "start 1"); + desc[eParam6].type = eParamTypeFix; + desc[eParam6].min = 0x00000000; + desc[eParam6].max = PARAM_SECONDS_MAX; + desc[eParam6].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam7].label, "loop 1"); + desc[eParam7].type = eParamTypeFix; + desc[eParam7].min = 0x00000000; + desc[eParam7].max = PARAM_SECONDS_MAX; + desc[eParam7].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam8].label, "direction 1"); + desc[eParam8].type = eParamTypeBool; + desc[eParam8].min = 0; + desc[eParam8].max = 1; + desc[eParam8].radix = 1; + + strcpy(desc[eParam9].label, "trig 1"); + desc[eParam9].type = eParamTypeBool; + desc[eParam9].min = 0; + desc[eParam9].max = 1; + desc[eParam9].radix = 1; + + strcpy(desc[eParam10].label, "level 2"); + desc[eParam10].type = eParamTypeAmp; + desc[eParam10].min = 0x00000000; + desc[eParam10].max = PARAM_AMP_MAX; + desc[eParam10].radix = 16; + + strcpy(desc[eParam11].label, "start 2"); + desc[eParam11].type = eParamTypeFix; + desc[eParam11].min = 0x00000000; + desc[eParam11].max = PARAM_SECONDS_MAX; + desc[eParam11].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam12].label, "loop 2"); + desc[eParam12].type = eParamTypeFix; + desc[eParam12].min = 0x00000000; + desc[eParam12].max = PARAM_SECONDS_MAX; + desc[eParam12].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam13].label, "direction 2"); + desc[eParam13].type = eParamTypeBool; + desc[eParam13].min = 0; + desc[eParam13].max = 1; + desc[eParam13].radix = 1; + + strcpy(desc[eParam14].label, "trig 2"); + desc[eParam14].type = eParamTypeBool; + desc[eParam14].min = 0; + desc[eParam14].max = 1; + desc[eParam14].radix = 1; + + strcpy(desc[eParam15].label, "level 3"); + desc[eParam15].type = eParamTypeAmp; + desc[eParam15].min = 0x00000000; + desc[eParam15].max = PARAM_AMP_MAX; + desc[eParam15].radix = 16; + + strcpy(desc[eParam16].label, "start 3"); + desc[eParam16].type = eParamTypeFix; + desc[eParam16].min = 0x00000000; + desc[eParam16].max = PARAM_SECONDS_MAX; + desc[eParam16].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam17].label, "loop 3"); + desc[eParam17].type = eParamTypeFix; + desc[eParam17].min = 0x00000000; + desc[eParam17].max = PARAM_SECONDS_MAX; + desc[eParam17].radix = PARAM_SECONDS_RADIX; + + strcpy(desc[eParam18].label, "direction 3"); + desc[eParam18].type = eParamTypeBool; + desc[eParam18].min = 0; + desc[eParam18].max = 1; + desc[eParam18].radix = 1; + + strcpy(desc[eParam19].label, "trig 3"); + desc[eParam19].type = eParamTypeBool; + desc[eParam19].min = 0; + desc[eParam19].max = 1; + desc[eParam19].radix = 1; +} + +// EOF diff --git a/modules/sample/params.h b/modules/sample/params.h new file mode 100644 index 000000000..c716ba843 --- /dev/null +++ b/modules/sample/params.h @@ -0,0 +1,50 @@ +#ifndef _ALEPH_MIX_PARAMS_H_ +#define _ALEPH_MIX_PARAMS_H_ + +#include "param_common.h" + +// define some constants here for the param descriptor code +// here, all the parameter ranges are pretty simple. +#define PARAM_AMP_MAX 0x7fffffff +#define PARAM_CV_MAX 0x7fffffff +#define PARAM_SLEW_MAX 0x7fffffff + +#define PARAM_SECONDS_MAX 0x003c0000 +#define PARAM_SECONDS_RADIX 7 + +// something pretty fast, but noticeable +#define PARAM_SLEW_DEFAULT 0x7ffecccc + +// enumerate parameters +// the order defined here must be matched in the descriptor ! +enum params { + + eParam0, + eParam1, + eParam2, + eParam3, + eParam4, + eParam5, + eParam6, + eParam7, + eParam8, + eParam9, + eParam10, + eParam11, + eParam12, + eParam13, + eParam14, + eParam15, + eParam16, + eParam17, + eParam18, + eParam19, + + eParamNumParams +}; + +// this is only defined by the descriptor helper program. +extern void fill_param_desc(ParamDesc* desc); + +#endif // header guard +// EOF diff --git a/modules/sample/sample.c b/modules/sample/sample.c new file mode 100644 index 000000000..af5b785c8 --- /dev/null +++ b/modules/sample/sample.c @@ -0,0 +1,329 @@ +/* + sample.c + aleph-bfin +*/ + +//-- aleph/common headers +#include "types.h" +#include + +//-- aleph/bfin-lib headers +// global variables +#include "bfin_core.h" +// cv output driver +#include "cv.h" +// gpio pin numbers +#include "gpio.h" +#include "fract_math.h" + +//-- dsp class headers +// simple 1-pole integrator +#include "filter_1p.h" + +// global declarations for module data +#include "module.h" +#include "params.h" + +#define BUFFERSIZE 0x1000000 +#define BUFFERSIZE_1 (0x1000000 - 1) +#define FR32_MAX1_2 0x3fffffff + + +typedef struct _sampleBuffer { + volatile fract32 *data; //pointer to data + u32 samples; //count of samples +} sampleBuffer; + +typedef struct _bufferHead { + sampleBuffer *buf; //pointer to buffer + s32 idx; //current idx +} bufferHead; + +static void buffer_init(sampleBuffer *buf, volatile fract32 *data, u32 samples); +static void buffer_head_init(bufferHead *head, sampleBuffer *buf); +static s32 buffer_head_play(bufferHead *head); + +typedef struct _mixData { + ModuleData super; + ParamData mParamData[eParamNumParams]; + + volatile fract32 sampleBuffer[BUFFERSIZE]; +} mixData; + +ModuleData *gModuleData; +mixData *data; +sampleBuffer onchipbuffer[4]; +u32 offset = 0; + +bufferHead heads[4]; +fract32 level[4] = { PARAM_AMP_MAX >> 2, PARAM_AMP_MAX >> 2, PARAM_AMP_MAX >> 2, PARAM_AMP_MAX >> 2 }; +fract32 start[4] = { 0xff, 0xff, 0xff, 0xff }; +fract32 loop[4] = { 48000, 48000, 48000, 48000 }; +fract32 direction[4] = { 1, 1, 1, 1 }; +fract32 trig[4] = { 0, 0, 0, 0 }; + +static inline void param_setup(u32 id, ParamValue v) { + gModuleData->paramData[id].value = v; + module_set_param(id, v); +} + +void module_init(void) { + data = (mixData*)SDRAM_ADDRESS; + gModuleData = &(data->super); + strcpy(gModuleData->name, "mix"); + gModuleData->paramData = data->mParamData; + gModuleData->numParams = eParamNumParams; + + u32 n, i; + + for(n=0; n<4; n++) + { + buffer_init(&(onchipbuffer[n]), data->sampleBuffer, BUFFERSIZE); + } + + for(n=0; n<4; n++) + { + buffer_head_init(&(heads[n]), &(onchipbuffer[n])); + } + + for(i=0; isampleBuffer[i] = 0x00000000; + } + + offset = 0; + + // init parameters + param_setup(eParam0, PARAM_AMP_MAX >> 2); + param_setup(eParam1, 0); + param_setup(eParam2, 48000); + param_setup(eParam3, 1); + param_setup(eParam4, 0); + + param_setup(eParam5, PARAM_AMP_MAX >> 2); + param_setup(eParam6, 0); + param_setup(eParam7, 48000); + param_setup(eParam8, 1); + param_setup(eParam9, 0); + + param_setup(eParam10, PARAM_AMP_MAX >> 2); + param_setup(eParam11, 0); + param_setup(eParam12, 48000); + param_setup(eParam13, 1); + param_setup(eParam14, 0); + + param_setup(eParam15, PARAM_AMP_MAX >> 2); + param_setup(eParam16, 0); + param_setup(eParam17, 48000); + param_setup(eParam18, 1); + param_setup(eParam19, 0); + +// for(n=0; n 0) + { + x[c] += direction[c]; + + if (x[c] > FR32_MAX) + { + x[c] = FR32_MAX1_2; + } + + heads[c].idx = add_fr1x32(y0, mult_fr1x32x32(x[c], sub_fr1x32(y1, y0))); + if (heads[c].idx > loop[c]) + { + heads[c].idx = start[c]; + } + if (trig[c]) + { + heads[c].idx = start[c]; + trig[c] = 0; + } + } + else + { + x[c] += -direction[c]; + + if (x[c] > FR32_MAX) + { + x[c] = FR32_MAX1_2; + } + + heads[c].idx = sub_fr1x32(y0, mult_fr1x32x32(x[c], sub_fr1x32(y1, y0))); + if (heads[c].idx < start[c]) + { + heads[c].idx = loop[c]; + } + if (trig[c]) + { + heads[c].idx = loop[c]; + trig[c] = 0; + } + } + + out[c] = mult_fr1x32x32(level[c], buffer_head_play(&(heads[c]))); + } +} + +// sample offset +void module_set_offset(ParamValue v) { + offset = v; +} + +// sample +void module_set_sample(ParamValue v) { + data->sampleBuffer[offset] = v; + offset++; +} + +// parameter set function +void module_set_param(u32 idx, ParamValue v) { + fract32 tmp; + + switch(idx) { + // level 0 + case eParam0: + level[0] = v; + break; + // start 0 + case eParam1: + tmp = v; + if (tmp < 0xff) tmp = 0xff; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + start[0] = tmp; + break; + // loop 0 + case eParam2: + tmp = v; + if (tmp < 0xff + 2) tmp = 0xff + 2; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + loop[0] = tmp; + break; + // direction 0 + case eParam3: + direction[0] = v; + break; + // trig 0 + case eParam4: + trig[0] = v; + break; + + // level 1 + case eParam5: + level[1] = v; + break; + // start 1 + case eParam6: + tmp = v; + if (tmp < 0xff) tmp = 0xff; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + start[1] = tmp; + break; + // loop 1 + case eParam7: + tmp = v; + if (tmp < 0xff + 2) tmp = 0xff + 2; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + loop[1] = tmp; + break; + // direction 1 + case eParam8: + direction[1] = v; + break; + // trig 1 + case eParam9: + trig[1] = v; + break; + + // level 2 + case eParam10: + level[2] = v; + break; + // start 2 + case eParam11: + tmp = v; + if (tmp < 0xff) tmp = 0xff; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + start[2] = tmp; + break; + // loop 2 + case eParam12: + tmp = v; + if (tmp < 0xff + 2) tmp = 0xff + 2; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + loop[2] = tmp; + break; + // direction 2 + case eParam13: + direction[2] = v; + break; + // trig 2 + case eParam14: + trig[2] = v; + break; + + // level 3 + case eParam15: + level[3] = v; + break; + // start 3 + case eParam16: + tmp = v; + if (tmp < 0xff) tmp = 0xff; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + start[3] = tmp; + break; + // loop 3 + case eParam17: + tmp = v; + if (tmp < 0xff + 2) tmp = 0xff + 2; + if (tmp > BUFFERSIZE_1) tmp = BUFFERSIZE_1; + loop[3] = tmp; + break; + // direction 3 + case eParam18: + direction[3] = v; + break; + // trig 3 + case eParam19: + trig[3] = v; + break; + + default: + break; + } +} + +void buffer_init(sampleBuffer *buf, volatile fract32 *data, u32 samples) { + buf->data = data; + buf->samples = samples; +} + +void buffer_head_init(bufferHead *head, sampleBuffer *buf) { + head->buf = buf; + head->idx = 0; +} + +s32 buffer_head_play(bufferHead *head) { + return head->buf->data[head->idx]; +} diff --git a/modules/sample/sample.lds b/modules/sample/sample.lds new file mode 100644 index 000000000..03da2913b --- /dev/null +++ b/modules/sample/sample.lds @@ -0,0 +1,256 @@ +/* +* Copyright (C) 2007, 2008 Analog Devices, Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice is included verbatim in any distributions. No written agreement, +* license, or royalty fee is required for any of the authorized uses. +* Modifications to this software may be copyrighted by their authors +* and need not follow the licensing terms described here, provided that +* the new terms are clearly indicated on the first page of each file where +* they apply. +*/ + +/* The default linker script, for single core blackfin standalone executables */ + +MEMORY +{ +MEM_L1_CODE : ORIGIN = 0xFFA00000, LENGTH = 0x10000 +MEM_L1_CODE_CACHE : ORIGIN = 0xFFA10000, LENGTH = 0x4000 +MEM_L1_SCRATCH : ORIGIN = 0xFFB00000, LENGTH = 0x1000 +MEM_L1_DATA_B : ORIGIN = 0xFF900000, LENGTH = 0x8000 +MEM_L1_DATA_A : ORIGIN = 0xFF800000, LENGTH = 0x8000 +MEM_L2 : ORIGIN = 0xFEB00000, LENGTH = 0x0 +} + +OUTPUT_FORMAT("elf32-bfin", "elf32-bfin", +"elf32-bfin") +OUTPUT_ARCH(bfin) +ENTRY(__start) + +SECTIONS +{ +/* Read-only sections, merged into text segment: */ +PROVIDE (__executable_start = 0x0); . = 0x0; +.interp : { *(.interp) } +.hash : { *(.hash) } +.dynsym : { *(.dynsym) } +.dynstr : { *(.dynstr) } +.gnu.version : { *(.gnu.version) } +.gnu.version_d : { *(.gnu.version_d) } +.gnu.version_r : { *(.gnu.version_r) } +.rel.init : { *(.rel.init) } +.rela.init : { *(.rela.init) } +.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } +.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } +.rel.fini : { *(.rel.fini) } +.rela.fini : { *(.rela.fini) } +.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } +.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } +.rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } +.rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } +.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } +.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } +.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } +.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } +.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } +.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } +.rel.ctors : { *(.rel.ctors) } +.rela.ctors : { *(.rela.ctors) } +.rel.dtors : { *(.rel.dtors) } +.rela.dtors : { *(.rela.dtors) } +.rel.got : { *(.rel.got) } +.rela.got : { *(.rela.got) } +.rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } +.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } +.rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } +.rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } +.rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } +.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } +.rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } +.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } +.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } +.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } +.rel.plt : { *(.rel.plt) } +.rela.plt : { *(.rela.plt) } + +.l2 : +{ +*(.l2 .l2.*) +} >MEM_L2 =0 + +.text : +{ +*(.text .stub .text.* .gnu.linkonce.t.* .l1.text .l1.text.*) +KEEP (*(.text.*personality*)) +/* .gnu.warning sections are handled specially by elf32.em. */ +*(.gnu.warning) +} >MEM_L1_CODE =0 + +.init : +{ +KEEP (*(.init)) +} >MEM_L1_CODE =0 +.plt : { *(.plt) } >MEM_L1_CODE +.fini : + +{ +KEEP (*(.fini)) +} >MEM_L1_CODE =0 + +PROVIDE (__etext = .); +PROVIDE (_etext = .); +PROVIDE (etext = .); +.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } >MEM_L1_DATA_A +.rodata1 : { *(.rodata1) } >MEM_L1_DATA_A + +.sdata2 : +{ +*(.sdata2 .sdata2.* .gnu.linkonce.s2.*) +} >MEM_L1_DATA_A + +.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } >MEM_L1_DATA_A +.eh_frame_hdr : { *(.eh_frame_hdr) } >MEM_L1_DATA_A +.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } >MEM_L1_DATA_A +.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >MEM_L1_DATA_A +/* Adjust the address for the data segment. We want to adjust up to +the same address within the page on the next page up. */ +. = ALIGN(0x1000) + (. & (0x1000 - 1)); +/* Exception handling */ +.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } >MEM_L1_DATA_A +.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >MEM_L1_DATA_A +/* Thread Local Storage sections */ +.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } >MEM_L1_DATA_A +.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } >MEM_L1_DATA_A +.preinit_array : +{ +PROVIDE_HIDDEN (___preinit_array_start = .); +KEEP (*(.preinit_array)) +PROVIDE_HIDDEN (___preinit_array_end = .); +} >MEM_L1_DATA_A +.init_array : +{ +PROVIDE_HIDDEN (___init_array_start = .); +KEEP (*(SORT(.init_array.*))) +KEEP (*(.init_array)) +PROVIDE_HIDDEN (___init_array_end = .); +} >MEM_L1_DATA_A +.fini_array : +{ +PROVIDE_HIDDEN (___fini_array_start = .); +KEEP (*(.fini_array)) +KEEP (*(SORT(.fini_array.*))) +PROVIDE_HIDDEN (___fini_array_end = .); +} >MEM_L1_DATA_A + +.ctors : +{ +/* gcc uses crtbegin.o to find the start of +the constructors, so we make sure it is +first. Because this is a wildcard, it +doesn't matter if the user does not +actually link against crtbegin.o; the +linker won't look for a file to match a +wildcard. The wildcard also means that it +doesn't matter which directory crtbegin.o +is in. */ +KEEP (*crtbegin*.o(.ctors)) +/* We don't want to include the .ctor section from +the crtend.o file until after the sorted ctors. +The .ctor section from the crtend file contains the +end of ctors marker and it must be last */ +KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) +KEEP (*(SORT(.ctors.*))) +KEEP (*(.ctors)) +} >MEM_L1_DATA_A + +.dtors : +{ +KEEP (*crtbegin*.o(.dtors)) +KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) +KEEP (*(SORT(.dtors.*))) +KEEP (*(.dtors)) +} >MEM_L1_DATA_A + +.jcr : { KEEP (*(.jcr)) } >MEM_L1_DATA_A +.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } >MEM_L1_DATA_A +.dynamic : { *(.dynamic) } >MEM_L1_DATA_A +.data : +{ +*(.data .data.* .gnu.linkonce.d.* .l1.data .l1.data.*) +KEEP (*(.gnu.linkonce.d.*personality*)) +SORT(CONSTRUCTORS) +} >MEM_L1_DATA_A +.data1 : { *(.data1) } >MEM_L1_DATA_A +.got : { *(.got.plt) *(.got) } >MEM_L1_DATA_A +/* We want the small data sections together, so single-instruction offsets +can access them all, and initialized data all before uninitialized, so +we can shorten the on-disk segment size. */ +.sdata : +{ +*(.sdata .sdata.* .gnu.linkonce.s.*) +} >MEM_L1_DATA_A +__edata = .; PROVIDE (_edata = .); +.sbss : +{ +__bss_start = .; +*(.dynsbss) +*(.sbss .sbss.* .gnu.linkonce.sb.*) +*(.scommon) +} >MEM_L1_DATA_A +.bss : +{ +*(.dynbss) +*(.bss .bss.* .gnu.linkonce.b.*) +*(COMMON) +/* Align here to ensure that the .bss section occupies space up to +_end. Align after .bss to ensure correct alignment even if the +.bss section disappears because there are no input sections. +FIXME: Why do we need it? When there is no .bss section, we don't +pad the .data section. */ +. = ALIGN(. != 0 ? 32 / 8 : 1); +__bss_end = .; +} >MEM_L1_DATA_A +. = ALIGN(32 / 8); +. = ALIGN(32 / 8); +__end = .; PROVIDE (_end = .); +/* Stabs debugging sections. */ +.stab 0 : { *(.stab) } +.stabstr 0 : { *(.stabstr) } +.stab.excl 0 : { *(.stab.excl) } +.stab.exclstr 0 : { *(.stab.exclstr) } +.stab.index 0 : { *(.stab.index) } +.stab.indexstr 0 : { *(.stab.indexstr) } +.comment 0 : { *(.comment) } +/* DWARF debug sections. +Symbols in the DWARF debugging sections are relative to the beginning +of the section so we begin them at 0. */ +/* DWARF 1 */ +.debug 0 : { *(.debug) } +.line 0 : { *(.line) } +/* GNU DWARF 1 extensions */ +.debug_srcinfo 0 : { *(.debug_srcinfo) } +.debug_sfnames 0 : { *(.debug_sfnames) } +/* DWARF 1.1 and DWARF 2 */ +.debug_aranges 0 : { *(.debug_aranges) } +.debug_pubnames 0 : { *(.debug_pubnames) } +/* DWARF 2 */ +.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } +.debug_abbrev 0 : { *(.debug_abbrev) } +.debug_line 0 : { *(.debug_line) } +.debug_frame 0 : { *(.debug_frame) } +.debug_str 0 : { *(.debug_str) } +.debug_loc 0 : { *(.debug_loc) } +.debug_macinfo 0 : { *(.debug_macinfo) } +/* SGI/MIPS DWARF 2 extensions */ +.debug_weaknames 0 : { *(.debug_weaknames) } +.debug_funcnames 0 : { *(.debug_funcnames) } +.debug_typenames 0 : { *(.debug_typenames) } +.debug_varnames 0 : { *(.debug_varnames) } + +__stack_end = ORIGIN(MEM_L1_SCRATCH) + LENGTH(MEM_L1_SCRATCH); + +/DISCARD/ : { *(.note.GNU-stack) } +} + diff --git a/modules/sample/version.mk b/modules/sample/version.mk new file mode 100644 index 000000000..f9ea5a843 --- /dev/null +++ b/modules/sample/version.mk @@ -0,0 +1,3 @@ +maj = 0 +min = 0 +rev = 0