Shop OBEX P1 Docs P2 Docs Learn Events
Need Advice from C Gurus — Parallax Forums

Need Advice from C Gurus

Those who know me know that I live and breath Spin. I write Spin programs most of the day, most days of the week. I like it.

That said... a few customers with C experience are wanting some of my starter programs in C. I'm making progress, but have a couple areas where I take advantage of Spin and am not sure how to crowbar it in to C.

For example. This bit of code appears in my embedded "background" object, hence gets called every millisecond.
var

  long  p_music
  long  nmillis


dat

  BPM           long    60

  Charge        long    N_G3, T_8TH,         N_C4, T_8TH, N_E4, T_8TH
                long    N_G4, T_8TH * 3 / 2, N_E4, T_8TH, N_G4, T_DHALF
                long    -1, -1   

  OneNote       long    0, 0, -1, -1                            ' for tone_on


pri play_music | nfreq

  if (p_music =< 0)                                             ' manual stop invoked?
    io.freq_out(0, SPKR, 0)
    return
           
  if (--nmillis > 0)                                            ' is note playing now?
    return

  nfreq := long[p_music]                                        ' get note
  p_music += 4                                                  ' advance to timing
  if (nfreq < 0)                                                ' if end
    longfill(@p_music, 0, 2)
    return

  nmillis := long[p_music] * 60 / BPM                           ' adjust timing for bpm
  p_music += 4                       

  io.freq_out(0, SPKR, nfreq)                                   ' start the note


I made the musical note and timing constants #defines and put them into their own .h file. That seems to be okay. The trick is the music. In my Spin program you can pass a pointer to an array of musical notes/times (the "Charge!" ditty is built in) and have it play. I'm not sure how to structure this in C.

Sorry for the beginner question. I appreciate the assist.

Comments

  • I have done little with C on the prop.

    Though if you compile your program as COG only is it not possible to just index from a pointer passed in PAR?
  • dgatelydgately Posts: 1,630
    edited 2017-03-13 18:35
    I let spin2cpp do the work. Possibly the convert from longfill to memset is not obvious when translating from Spin to C...
    spin2cpp --ccode test.spin
    
    void test_play_music()
    {
      int32_t   nfreq;
      if (p_music <= 0) {                    // manual stop invoked?                                               
        test_freq_out(0, TEST_SPKR, 0);
        return;
      }
    
      if ((--nmillis) > 0) {                 // is note playing now?                                                        
        return;
      }
                                                                  
      nfreq = ((int32_t *)p_music)[0];       // get note
      p_music = p_music + 4;                 // advance to timing
      if (nfreq < 0) {                       // if end                                           
        memset( (void *)(&p_music), 0, sizeof(int32_t)*2);
        return;
      }
                                                                  
      nmillis = (((int32_t *)p_music)[0] * 60) / ((int32_t *)&dat[0])[0];       // adjust timing for bpm
      p_music = p_music + 4;                                                    // start the note
      test_freq_out(0, TEST_SPKR, nfreq);
    }
    


    dgately
  • It looks like p_music wants to be a pointer to integers, so you would have something like:
    int Charge[] = {
       N_G3, T_8TH, N_C4,
       /* and so on... */
    };
    int *p_music;
    
    void play_music() {
       n_freq = *p_music++;
       nmillisec = (*p_music++) * 60 / BPM;
       freq_out(0, SPKR, n_freq);
    }
    /* somewhere in initialization */
    p_music = Charge;
    
    C's handling of pointer accesses is very much like Spin's, except that C pointers are typed so "++" advances to the next element rather than the next byte (so you just do "p_music++" rather than "p_music += 4").

  • JasonDorieJasonDorie Posts: 1,930
    edited 2017-03-13 18:48
    In C/C++, if you declare an array of something, you can pass the pointer by simply passing the name of the array, instead of passing a specific element, like this:
    void PrintArray( long * ptrToNumbers )   // long * means "pointer to a long"
    {
      int index = 0;
      while( ptrToNumbers[index] != -1 )
      {
        // printf is "print formatted", and %d means "decimal number" - it will be
        // replaced by one of the arguments after the quoted string
        printf( "Number at index %d is : %d\n", index, ptrToNumbers[index] );
        index += 1;
      }
    }
    
    void main(void)
    {
      // declare the array with contents, -1 is the terminating element so you don't have to pass the size
      long MyArray[] = {5, 6, 7, 8, 9, 10, -1};
    
      // pass the pointer to the array to the printing function
      PrintArray( MyArray );
    }
    
  • And yes, spin2cpp is useful for this kind of thing. You can use the spincvt GUI if you don't like command lines. Select "C Output" under options, then File > Open Spin File and select your .spin file. The Spin code will be loaded in the left hand pane, and the converted C code will appear on the right hand pane (with the command line used to do the conversion printed on the bottom).
  • twm47099twm47099 Posts: 867
    edited 2017-03-13 19:28
    Eric,
    What is the link to the spin2cpp programs?

    Thanks
    Tom
  • twm47099 wrote: »
    Eric,
    What is the link to the spin2cpp programs?

    Thanks
    Tom

    The source code is at https://github.com/totalspectrum/spin2cpp/.
    There are binary releases here.


  • i'm not a C guru but i found that book really good to brush up my rusty C and catch up with C99 standard.
    21st Century C

    For instance to initialize a structure :

    MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 }; (from a stack overflow answer but the book describes this more accurately)
    Other members are initialized as zero
  • laurent974 wrote: »
    For instance to initialize a structure :

    MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

    That's new syntax for me! Thanks for sharing :)
  • laurent974 wrote: »
    i'm not a C guru but i found that book really good to brush up my rusty C and catch up with C99 standard.
    21st Century C

    For instance to initialize a structure :

    MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 }; (from a stack overflow answer but the book describes this more accurately)
    Other members are initialized as zero
    Wow that is a rather verbose syntax. Did not know that was possible, thank you.

    I really need to see about C on the Propeller, seeing some of the examples there would be very little change between C code for WiringPi on the Raspberry Pi and code for the Propeller in many cases, this could definitely make for some interesting possibilities.
  • Heater.Heater. Posts: 21,230
    How is that verbose syntax? It's about the same as doing a similar job is many other languages.

    E.g Javascript:

    let a = {flag : true, value : 123, stuff : 0.456};

    Or Python:

    a = {'flag': True, 'value': 123, 'stuff': 0.456}

    What language does it more concisely ?
Sign In or Register to comment.