store 16bit variable to 8bit FILE_Writebuffer

Try something like this:

FILE_ReadBuffer((u8*)loop, 8 * sizeof(store_t));

and

FILE_WriteBuffer((u8*)loop, 8 * sizeof(store_t));

the trick is to use “sizeof”, that calculates the data size of the structure “store_t” in bytes. Multiplying it by 8 if you want to read/write 8 of these structures at once. Make sure, that the variable “loop” is big enough to hold the data. 

Good luck and many greets,
Peter

 

2 hours ago, Hawkeye said:

Try something like this:

FILE_ReadBuffer((u8*)loop, 8 * sizeof(store_t));

and

FILE_WriteBuffer((u8*)loop, 8 * sizeof(store_t));

 

FILE_WriteBuffer((u8 *)loop[track], sizeof(store_t));

for a single track…

best!

2 Likes

5 hours ago, Hawkeye said:

FILE_ReadBuffer((u8*)loop, 8 * sizeof(store_t));

FILE_WriteBuffer((u8*)loop, 8 * sizeof(store_t));

the trick is to use “sizeof”, that calculates the data size of the structure “store_t” in bytes. Multiplying it by 8 if you want to read/write 8 of these structures at once. Make sure, that the variable “loop” is big enough to hold the data.

would assume that all my tracks saved in a single file, and thats not the case, since i need to load the clips independendly for launching via BLM, but also need to load the clips via Program-change also

so it ends up with:

case 2: //LOAD all Clips - FOR P R O G R A M C H A N G E for( t=0; t\<8; t++) { MUTEX\_SDCARD\_TAKE; sprintf ( filepathL, "sq/%d-%d.sq", t, clip ); FILE\_ReadOpen ( &midifile\_fi, filepathL ); FILE\_ReadBuffer ( (u8 \*)file\_type,4 ); FILE\_ReadBuffer ( (u8 \*)loop[t], sizeof(store\_t) ); FILE\_ReadClose ( &midifile\_fi ); MUTEX\_SDCARD\_GIVE; //Calculate new Loop Lengths Loop[t]= loop[t].length \* MainLoop; }

2 hours ago, Antichambre said:

FILE_WriteBuffer((u8 *)loop[track], sizeof(store_t));

for a single track…

best!

 

by the way, do i need that

FILE_WriteBuffer( (u8  *)file_type,    4 ); //“SQ01” = 4 Positons  

for what platforms do i need a filetype?

compiler says for the line: FILE_WriteBuffer((u8 *)loop[track], sizeof(store_t));     :

Quote

app.c:839:1: error: cannot convert to a pointer type

 

It seems you solved it, just as Bruno recommended it, with the index loop[t] you can (and did) of course address only a single struct and can read/write that at any time, even when the app is running.

Quote

by the way, do i need that

FILE_WriteBuffer( (u8  *)file_type,    4 ); //“SQ01” = 4 Positons  

for what platforms do i need a filetype?

A filetype generally helps you to reidentify which kind of revision a file has - as it is binary, structs may change and you may not be able to load old data in a new version, so in the loader you can compare the filetype to the expected version.

Quote

app.c:839:1: error: cannot convert to a pointer type

That happens for all non-array datastructures like plain integers. You need to take their address with the ampersand operator (that can then by typecasted to a u8 pointer) and write

FILE_WriteBuffer( (u8  *)&file_type,    4 ); //“SQ01” = 4 Positons  

Many greets!
Peter

ok understand, i let the the file describtion in…

oje…

there is something wrong with the code,

http://wiki.midibox.org/lib/exe/fetch.php?media=phatline:seq-melody-footboard-beta.zip

 

when i make arrays with 8x512, or arrays with 8x1024, the Files on SD-Card is always 5,6kb size, also on 1024 i got hardfaults when copy those structs into arrays (copy paste clear clips), by 512 no hardfault

 typedef struct storage { u16 PB [512]; u8 SEQ[512] [8]; u8 MSQ[512]; char leader; char virgin; u8 length; u8 decay; u8 rythm; u16 bpm; } store\_t; no difference in SD-File-Size! typedef struct storage { u16 PB [1024]; u8 SEQ[1024] [8]; u8 MSQ[1024]; char leader; char virgin; u8 length; u8 decay; u8 rythm; u16 bpm; } store\_t;

 

also i initialize all Arrays, but actual most of them (all except the first member loop[0] in the program are 0-out

void APP\_Init(void){ //initalize 8 Clips with standart values u8 a = 0; for ( a=0; a\>8; a++ ) { loop[a].leader = 0; loop[a].virgin = 1; loop[a].length = 1; loop[a].decay = 60; loop[a].rythm = 4; loop[a].bpm = 120; //initiate Pitchbend u16 b; for(b=0; b\<512; b++) { loop[a].PB[b] = 8192; } }; //Initiate Pitchbend - copy paste buffer u16 b; for(b=0; b\<512; b++) { PB\_copy[b] = 8192; } }

 

the 1024 thing i think is clear, it takes to long to calculate all the data, i would need something like a xtask… but i dont figured out how to make out of a

Quote

static void Edit_Clip(u8 track, u16 clip, u16 job);     a    static void Edit_Clip       (void *pvParameters);

i know:

Quote

    xTaskCreate(Edit_Clip,  (signed portCHAR *)“Edit_Clip”, 256,  NULL, PRIORITY_Counter, NULL); 

i use such things for counters in ms tact (decay-counters, blink blink…), but not for a function that gets called, work something out, and done…

for example:

static void Decay(void \*pvParameters){ //Send Note OFFs after a while portTickType xLastExecutionTime; xLastExecutionTime = xTaskGetTickCount(); // Initialise the xLastExecutionTime variable on task entry while( 1 ) { vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK\_RATE\_MS); for(DcyNteCount = 1; DcyNteCount \< 128; DcyNteCount++) { for(DcyTrkCount = 0; DcyTrkCount \< 8; DcyTrkCount++) { if (MeloDecayTIMER[DcyTrkCount][DcyNteCount] != 0) { MeloDecayTIMER[DcyTrkCount][DcyNteCount] --; if (MeloDecayTIMER[DcyTrkCount][DcyNteCount] == 0) { MIOS32\_MIDI\_SendNoteOff(MelPortOut, MeloOutCh[DcyTrkCount], DcyNteCount, 0); MIOS32\_MIDI\_SendNoteOn (MelPortOut, MeloOutCh[DcyTrkCount], DcyNteCount, 0);}} }} }//End While }//End TICK 0 \>\>\> 1ms Task...

 

Hi,

in this line is the problem with the failed initialization, can you find it? :slight_smile:

Quote

for ( a=0; a>8; a++ ) {

Regarding the identical file-sizes for two different structs: the structs look good. You could output the value of sizeof(store_t) either to your LCD or as a MIOS debug message to the MIOS terminal - i bet the value looks good and it is a problem with the file writing code.
Also make sure, you’ve recompiled the structure definition file after changing the structure size, if the linker links to an old object file, the sizeof calculation may be wrong.

Regarding background tasks - which data are you calculating, and how often do you need to recalculate it? The core is really quite fast, in the loopa context for example, i can output/calculate on something like 16kbytes in every screen refresh cycle (something like 30-50hz). I’ve “hooked” the screen output routine to an xtask and it works nicely without overloading the rest of the system. If you change data, that is used in other threads/tasks, you need to protect by a mutex though. It is a bit of an advanced topic, that’s why i ask why you cannot calculate in the main task of the running app/sequencer.

Many greets,
Peter

aja        a < 8        of course, thx!

 

Edit: read/write on SD-Card is working fine!

 MUTEX\_SDCARD\_TAKE; //Write to File sprintf(file\_path, "msp/%d-%d.msp", track, clip); FILE\_WriteOpen ( file\_path, 16 ); FILE\_WriteBuffer( (u8 \*)&file\_type, 4 ); FILE\_WriteBuffer( (u8 \*)&loop[track], sizeof(store\_t) ); FILE\_WriteClose (); MUTEX\_SDCARD\_GIVE;

 

@ Background-tasks

function example which make a hardfault when using 1024,  when calling it… i call it once a time  with a button press on the UI (DIN) > see code below

but also will need such things for mooving sequencer data forward in loop, or backwards, or copy step 0-15 to all other 512 steps in a musically way > means could be a wild button orgie…

in App.h: typedef struct storage { // to optimize SD-Load-Time, each clips data is stored in this struct u16 PB [512]; // Pitchband inital = 8192 = No Pitchbend! u8 SEQ[512] [8]; // 512Steps, 8NotePolyphony u8 MSQ[512]; // Motion-SEQ of one CC ...eg.:Control-Wheel of Keyboard char leader; // Programchange able? - only 1 of 4 Song-Clips can send Programchanges via BLMatrix char virgin; // is there any data in the clip? need to display on a ButtonLed Matrix-Launcher u8 length; // 1x16, 2x16... u8 decay; // 60ms... could be set with Encoder, but I dont need a variable, since the melody out will be used by the Triggermatrix... u8 rythm; // 4x4=16, 5x3=15 usw... to calculate maximal duration per UI-matrix page u16 bpm; } store\_t; extern store\_t loop[8]; in app.c: u16 SEQ\_copy[512][8] = {{}}; //Copy actual Track into ClipboardBuffer u16 MSQ\_copy[512] = {}; //Copy actual Track into ClipboardBuffer u16 PB\_copy [512] = {}; //Copy actual Track into ClipboardBuffer u16 tact\_info\_copy[32] = {}; //Copy bpm, loop length, tact and so on // E D I T C L I P D A T A static void Edit\_Clip(u8 track, u16 clip, u16 job){ u16 c = 0; u16 x = 0; switch(job) { // Clear case 0: for( c=0; c\<512; c++ ) { if(edit[0] == 1) { loop[track].PB[c] = 8192; } // = no Pitch Bend if(edit[1] == 1) {for( x=0; x\<8; x++ ) { loop[track].SEQ[c][x] = 0; } } // = no Note if(edit[2] == 1) {loop[track].MSQ[c] = 0; } // = no Control Change } break; // Copy case 1: for( c=0; c\<512; c++ ) { if(edit[0] == 1) { PB\_copy[c] = loop[track].PB[c];} // PB if(edit[1] == 1) { for( x=0; x\<8; x++ ) { SEQ\_copy[c][x] = loop[track].SEQ[c][x]; } } // NOTE if(edit[2] == 1) { MSQ\_copy[c] = loop[track].MSQ[c];} // MSQ } if(edit[3] == 1) { tact\_info\_copy[0] = loop[track].leader; tact\_info\_copy[1] = loop[track].virgin; tact\_info\_copy[2] = loop[track].length; tact\_info\_copy[3] = loop[track].decay; tact\_info\_copy[4] = loop[track].rythm; tact\_info\_copy[5] = loop[track].bpm; } break; // Paste case 2: for( c=0; c\<512; c++ ) { if(edit[0] == 1) { loop[track].PB[c] = PB\_copy[c];} // PB if(edit[1] == 1) { for( x=0; x\<8; x++ ) { loop[track].SEQ[c][x] = SEQ\_copy[c][x]; } } // NOTE if(edit[2] == 1) { loop[track].MSQ[c] = MSQ\_copy[c]; } // MSQ } if(edit[3] == 1) { loop[track].leader = tact\_info\_copy[0]; loop[track].virgin = tact\_info\_copy[1]; loop[track].length = tact\_info\_copy[2]; loop[track].decay = tact\_info\_copy[3]; loop[track].rythm = tact\_info\_copy[4]; loop[track].bpm = tact\_info\_copy[5]; } break; } }

also the code above is working ifne :wink:

Good to see, that there is progress! :slight_smile:

I can’t check the whole code, but there might be out-of-bound memory accesses somewhere, that will usually result in a crash sooner or later. It might just work with an array size of 512, but would crash when using 1024, welcome to the beauty of C :-).

You need to double-check all write-accesses (indices).

A good strategy here is to “comment out code”, and see when the problem stops. Then look at the commented out segment and subdivide it, comment out more, you should be able to find it like that.

Also regarding speed, as you are only doing small assignment loops up to 1024 or 512x8 or so, this is easily fast enough to be executed on a button press, for that there is no need of a background task. You could even do this every sequencer tick or so in the main thread and it would still probably be fast enough - multithreading just adds even more difficult to detect problems, avoid it for now if you can.

Many greets and good luck!
Peter


sorry I was on the way back home… But Peter was here.

This is what I propose you, I compile it successfully and call Edit function from App_Background without any Hardfault, I verify reset and copy subfunction by SendDebugMessage… All is fine.

your whole modified project: http://www.midibox.org/dokuwiki/lib/exe/fetch.php?media=phatline:seq-melody-footboard_copie.zip
in details:
first better to use same struct as clipboard:

//Card-Clip-Container store\_t loop[8]; store\_t loop\_copy; //instead of // u16 SEQ\_copy[512][8] = {{}}; //Copy actual Track into ClipboardBuffer // u16 MSQ\_copy[512] = {}; //Copy actual Track into ClipboardBuffer // u16 PB\_copy [512] = {}; //Copy actual Track into ClipboardBuffer // u16 tact\_info\_copy[32] = {}; //Copy bpm, loop length, tact and so on 

better using bits for edit flags, you will understand why after:

// char edit[4] = {1,1,1,1}; //PB, SEQ, MSQ, Beatstructure, Edit Flags for copy paste clear u8 edit = 0xff; //PB, SEQ, MSQ, Beatstructure, Edit Flags for copy paste clear

to initialise your tracks in APP_Init:

//initalize 8 Tracks with standard values u8 a; edit= 0x0f; for ( a=0; a\<8; a++ )Edit\_Clip(a, 0, 0);

This is what I did to check edit function at startup:

void APP\_Background(void){ #ifdef APP\_EDIT\_TEST edit= 0x0f; Edit\_Clip(0, 0, 1); u16 c, x; for( c=0; c\<512; c++ ) { MIOS32\_MIDI\_SendDebugMessage("PB: %d: %d to %d.", c, loop[0].PB[c] ,loop\_copy.PB[c]); for(x=0; x\<8; x++)MIOS32\_MIDI\_SendDebugMessage("SEQ: %d: %d to %d.", c, loop[0].SEQ[c][x] ,loop\_copy.SEQ[c][x]); MIOS32\_MIDI\_SendDebugMessage("MSQ: %d: %d to %d.", c, loop[0].MSQ[c] ,loop\_copy.MSQ[c]); MIOS32\_MIDI\_SendDebugMessage("leader: %d: %d to %d.", c, loop[0].leader,loop\_copy.leader); MIOS32\_MIDI\_SendDebugMessage("virgin: %d: %d to %d.", c, loop[0].virgin,loop\_copy.virgin); MIOS32\_MIDI\_SendDebugMessage("length: %d: %d to %d.", c, loop[0].length, loop\_copy.length); MIOS32\_MIDI\_SendDebugMessage("decay: %d: %d to %d.", c, loop[0].decay, loop\_copy.decay); MIOS32\_MIDI\_SendDebugMessage("rythm: %d: %d to %d.", c, loop[0].rythm, loop\_copy.rythm); MIOS32\_MIDI\_SendDebugMessage("bpm: %d: %d to %d.", c, loop[0].bpm, loop\_copy.bpm); } #endif // endless loop while( 1 ) {} }

Result:

Working with edit bits flags, You have to verify this cause I haven’t got the necessary hardware.

  • In APP_SRIO_ServicePrepare

    MIOS32_DOUT_PinSet( 56, edit & 0x01); MIOS32_DOUT_PinSet( 57, (edit>>1) & 1); MIOS32_DOUT_PinSet( 58, (edit>>2) & 1); MIOS32_DOUT_PinSet( 59, (edit>>1) & 1); //instead of // MIOS32_DOUT_PinSet( 56, edit[0]); // MIOS32_DOUT_PinSet( 57, edit[1]); // MIOS32_DOUT_PinSet( 58, edit[2]); // MIOS32_DOUT_PinSet( 59, edit[3]);

  • In APP_DIN_NotifyToggle

    case8: edit ^= (1<<0);break;// Act on: PB case9: edit ^= (1<<1);break;// Act on: SEQ case 10: edit ^= (1<<2);break;// Act on: MSQ-CC case 11: edit ^= (1<<3);break;// Act on: Beat structure like Loop Length BPM and so on //instead of // case 8: edit[0] =! edit[0]; break; // Act on: PB // case 9: edit[1] =! edit[1]; break; // Act on: SEQ // case 10: edit[2] =! edit[2]; break; // Act on: MSQ-CC // case 11: edit[3] =! edit[3]; break; // Act on: Beat structure like Loop Length BPM and so on

Now this is your modified edit function:
Note: better to remove clip variable if you do not use it

// E D I T C L I P D A T A static void Edit\_Clip(u8 track, u16 clip, u16 job){ // clip is not used in this procedure better to remove it ;) switch(job) { // Reset(Clear) case 0: if(edit & (1\<\<0))wmemset(loop[track].PB, (u32)((8192\<\<16) + 8192), (sizeof (loop[track].PB))/4); // reset Pitch Bend if(edit & (1\<\<1))memset(loop[track].SEQ, 0, sizeof loop[track].SEQ);// reset Note if(edit & (1\<\<2))memset(loop[track].MSQ, 0, sizeof loop[track].MSQ);// reset Control Change if(edit & (1\<\<3)){// reset track parameters loop[track].leader = 0; loop[track].virgin = 1; loop[track].length = 1; loop[track].decay = 60; //maximal 256 since we use u8 integer type loop[track].rythm = 4; loop[track].bpm = 120; } break; // Copy case 1: if(edit & 0x0f)memcpy(&loop\_copy, &loop[track], sizeof loop\_copy);// copy full track else{ if(edit & (1\<\<0))memcpy(loop\_copy.PB, loop[track].PB, sizeof loop\_copy.PB);// copy Pitch Bend if(edit & (1\<\<1))memcpy(loop\_copy.SEQ, loop[track].SEQ, sizeof loop\_copy.SEQ);// copy Note if(edit & (1\<\<2))memcpy(loop\_copy.MSQ, loop[track].MSQ, sizeof loop\_copy.MSQ);// copy Control Change if(edit & (1\<\<3)){// copy track parameters loop\_copy.leader = loop[track].leader; loop\_copy.virgin = loop[track].virgin; loop\_copy.length = loop[track].length; loop\_copy.decay = loop[track].decay; loop\_copy.rythm = loop[track].rythm; loop\_copy.bpm = loop[track].bpm; } } break; // Paste case 2: if(edit & 0x0f)memcpy(&loop[track], &loop\_copy, sizeof loop\_copy);// paste full track else{ if(edit & (1\<\<0))memcpy(loop[track].PB, loop\_copy.PB, sizeof loop[track].PB);// paste Pitch Bend if(edit & (1\<\<1))memcpy(loop[track].SEQ, loop\_copy.SEQ, sizeof loop[track].SEQ);// paste Note if(edit & (1\<\<2))memcpy(loop[track].MSQ, loop\_copy.MSQ, sizeof loop[track].MSQ);// paste Control Change if(edit & (1\<\<3)){// paste track parameters loop[track].leader = loop\_copy.leader; loop[track].virgin = loop\_copy.virgin; loop[track].length = loop\_copy.length; loop[track].decay = loop\_copy.decay; loop[track].rythm = loop\_copy.rythm; loop[track].bpm = loop\_copy.bpm; } } break; } } 

This must be faster, as you can see, if edit has bit 0 to 3 @1 then the whole track will be copied or pasted in one unique memcpy :wink:

Voilà!

oups!
change

MIOS32\_DOUT\_PinSet( 59, (edit\>\>1) & 1);

to

MIOS32_DOUT_PinSet( 59, (edit>>3) & 1);
if(edit & 0x0f)memcpy(&loop\_copy, &loop[track], sizeof loop\_copy); 

clever i like that

but i planned it more like:  check which things have to copyied, so i can copy PB+NOTES, but not CC+Loop-Information, (for default)

if i get it right: in your thought i can always copy only one thing: PB, All, Notes or Loop-Info

but i can still use memcpy with for example:

if( (edit[0]==1) && (edit[1]==1) && (edit[1]==1) && (edit[1]==1) ) memcpy(&loop\_copy, &loop[track], sizeof loop\_copy); 

 

THX for your help guys!

for the rest i will take me time on 23.12… today we make fire in the snow, and celebrate the 21.12 to restart the sun-circle happy new sun year, skol!

5 hours ago, Phatline said:

but i planned it more like:  check which things have to copyied, so i can copy PB+NOTES, but not CC+Loop-Information, (for default)

if i get it right: in your thought i can always copy only one thing: PB, All, Notes or Loop-Info

but i can still use memcpy with for example:

if( (edit[0]==1) && (edit[1]==1) && (edit[1]==1) && (edit[1]==1) ) memcpy(&loop_copy, &loop[track], sizeof loop_copy);

 

if (edit & 0x03) then you will copy only PB + Notes and at the same time, using bits is just a better way to detect if the whole track has to be copied and using memcpy only one time, for other values it’s the same as you did before.

“happy new sun year” to you too :wink:

best
Bruno

hm i get a error:

app.c:1094:13: warning: implicit declaration of function 'wmemset' [-Wimplicit-function-declaration]

if(edit & (1\<\<0))wmemset(loop[track].PB, (u32)((8192\<\<16) + 8192), (sizeof (loop[track].PB))/4); // reset Pitch Bend

 

when i then add:

include <wchar.h>    to app.c

then error:

Quote

app.c:1169:13: warning: passing argument 1 of ‘wmemset’ from incompatible pointer type [enabled by default]

In file included from app.c:23:0:

/home/triggermatrix/mios32_toolchain/bin/../lib/gcc/arm-none-eabi/4.7.4/../../../../arm-none-eabi/include/wchar.h:108:10: note: expected ‘wchar_t *’ but argument is of type ‘u16 *’

 

 

should i change this:

 typedef struct storage { u16 PB [512]; u8 SEQ[512] [8]; u8 MSQ[512]; char leader:1; char virgin:1; u8 length; u8 decay; u8 rythm; u16 bpm; } store\_t;

to this:

 typedef struct storage { wchar\_t PB PB [512]; u8 SEQ[512] [8]; u8 MSQ[512]; char leader:1; char virgin:1; u8 length; u8 decay; u8 rythm; u16 bpm; } store\_t;

hm what size has this wchar_t?

19 minutes ago, Phatline said:

hm i get a error:

app.c:1094:13: warning: implicit declaration of function ‘wmemset’ [-Wimplicit-function-declaration]

if(edit & (1<<0))wmemset(loop[track].PB, (u32)((8192<<16) + 8192), (sizeof (loop[track].PB))/4); // reset Pitch Bend

This is just a warning, it works…
But ok to be sure…
Don’t change your structure. Just include the wchar.h library
and add a (wchar_t *) to wmemset address target:

if(edit & (1\<\<0))wmemset((wchar\_t \*)loop[track].PB, (u32)((8192\<\<16) + 8192), (sizeof (loop[track].PB))/4); // reset Pitch Bend

Normally no more warning and it must work…

22 minutes ago, Phatline said:

hm what size has this wchar_t?

wchar_t size depends on the machine and compiler… But 4 bytes wide, 32 bits here, that’s the reason sizeof is divided by 4.

Joyeux Noel !!!
Bruno

1 Like