Sound Generator Library

Fork of Sound_Generator by GR-PEACH_producer_meeting

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers piano4int.cpp Source File

piano4int.cpp

00001 /******************************************************************************
00002 * DISCLAIMER
00003 * This software is supplied by Renesas Electronics Corporation and is only
00004 * intended for use with Renesas products. No other uses are authorized. This
00005 * software is owned by Renesas Electronics Corporation and is protected under
00006 * all applicable laws, including copyright laws.
00007 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
00008 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
00009 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00010 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
00011 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
00012 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
00013 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
00014 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
00015 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00016 * Renesas reserves the right, without notice, to make changes to this software
00017 * and to discontinue the availability of this software. By using this software,
00018 * you agree to the additional terms and conditions found by accessing the
00019 * following link:
00020 * http://www.renesas.com/disclaimer
00021 * Copyright (C) 2012 - 2015 Renesas Electronics Corporation. All
00022 * rights reserved.
00023 ******************************************************************************/
00024 
00025 /******************************************************************************
00026 Includes   <System Includes> , "Project Includes"
00027 ******************************************************************************/
00028 #include <stdio.h>
00029 #include <ctype.h>
00030 #include <stdint.h>
00031 extern "C" {
00032 #include "iodefine.h"
00033 #include "dev_drv.h"
00034 #include "devdrv_sdg.h"
00035 }
00036 #include "mbed.h"
00037 #include "PinNames.h"
00038 
00039 #include "piano4int.h"
00040 
00041 /******************************************************************************
00042 Macro definitions
00043 ******************************************************************************/
00044 #define ASSERT( eval )                          \
00045     if (!(eval)) {                              \
00046         printf(                                 \
00047             "%s: failed! at %d in %s\n",        \
00048             #eval,                              \
00049             __LINE__,                           \
00050             __FILE__);                          \
00051     }
00052 
00053 /* message to caller */
00054 #define     UNIT_MSG    (32)
00055 
00056 
00057 /******************************************************************************
00058 Typedef definitions
00059 ******************************************************************************/
00060 /* a sound generator unit */
00061 typedef struct {
00062     uint16_t        speed;          /* count of a tempo     */
00063     uint8_t         loudness;       /* current loudness     */
00064     uint16_t        count;          /* remain of time       */
00065     NOTE            note;           /* a next note          */
00066     const int8_t    *score;         /* a next score         */
00067     const int8_t    *top;           /* top of a score       */
00068     uint8_t         channel;        /* channel number       */
00069 #ifdef UNIT_MSG
00070     char            msg[UNIT_MSG];  /* message              */
00071 #endif
00072 } UNIT;
00073 
00074 
00075 /******************************************************************************
00076 Imported global variables and functions (from other files)
00077 ******************************************************************************/
00078 
00079 
00080 /******************************************************************************
00081 Exported global variables and functions (to be accessed by other files)
00082 ******************************************************************************/
00083 
00084 
00085 /******************************************************************************
00086 Private global variables and functions
00087 ******************************************************************************/
00088 /* interrupt routine */
00089 static void play_score(void);
00090 
00091 
00092 /* all work area for piano */
00093 struct {
00094     UNIT            unit[SDG_CH_TOTAL];
00095     uint16_t        fin;
00096     Ticker          metronome;          /* base tempo */
00097     PIANO4INT_CB    callback;
00098 } pianoT;
00099 
00100 
00101 /* init params for sound generator */
00102 static const struct {
00103     uint16_t    channel;
00104     R_SDG_CLOCK clock;
00105 } unitHW[SDG_CH_TOTAL] = {
00106     {   DEVDRV_CH_0, R_SDG_CLOCK_4 },
00107     {   DEVDRV_CH_1, R_SDG_CLOCK_4 },
00108     {   DEVDRV_CH_2, R_SDG_CLOCK_4 },
00109     {   DEVDRV_CH_3, R_SDG_CLOCK_4 },
00110 };
00111 
00112 
00113 /* dummy entry of score (no sounds)*/
00114 static const int8_t noscore[] = "";
00115 
00116 /* parameters of a rest */
00117 static const NOTE   rest4 = {
00118     0,  /* tone         */
00119     0,  /* sfs          */
00120     0,  /* loud         */
00121     0,  /* attenuation  */
00122 };
00123 
00124 
00125 /* table of notes */
00126 static const struct {
00127     uint8_t     tone;
00128     uint8_t     sfs;
00129 } note_timing[MAXOCTAVE][MAXNOTE] = {
00130     {   /* octave 0 */
00131         {   0,   0 },  /* -A  */
00132         {   0,   0 },  /* -A# */
00133         {   0,   0 },  /* -B  */
00134         { 124, 255 },  /* -C  */
00135         { 117, 255 },  /* -C# */
00136         { 111, 255 },  /* -D  */
00137         { 105, 255 },  /* -D# */
00138         {  99, 255 },  /* -E  */
00139         {  93, 255 },  /* -F  */
00140         {  88, 255 },  /* -F# */
00141         {  83, 255 },  /* -G  */
00142         {  78, 255 },  /* -G# */
00143         {   0,   0 },  /* -R  */
00144     },
00145     {   /* octave 1 */
00146         {  86, 220 },  /*  A  */
00147         {  81, 220 },  /*  A# */
00148         {  76, 220 },  /*  B  */
00149         {  72, 220 },  /*  C  */
00150         {  68, 220 },  /*  C# */
00151         {  64, 220 },  /*  D  */
00152         {  60, 220 },  /*  D# */
00153         {  57, 220 },  /*  E  */
00154         {  54, 220 },  /*  F  */
00155         {  51, 220 },  /*  F# */
00156         {  48, 220 },  /*  G  */
00157         {  45, 220 },  /*  G# */
00158         {   0,   0 },  /*  R  */
00159     },
00160     {   /* octave 2 */
00161         {  49, 190 },  /* +A  */
00162         {  47, 190 },  /* +A# */
00163         {  44, 190 },  /* +B  */
00164         {  41, 190 },  /* +C  */
00165         {  39, 190 },  /* +C# */
00166         {  37, 190 },  /* +D  */
00167         {  35, 190 },  /* +D# */
00168         {  33, 190 },  /* +E  */
00169         {  31, 190 },  /* +F  */
00170         {  29, 190 },  /* +F# */
00171         {  27, 190 },  /* +G  */
00172         {  26, 190 },  /* +G# */
00173         {   0,   0 },  /* +R  */
00174     },
00175     {   /* octave 3 */
00176         {  31, 150 },  /* *A  */
00177         {  29, 150 },  /* *A# */
00178         {  28, 150 },  /* *B  */
00179         {  26, 150 },  /* *C  */
00180         {  25, 150 },  /* *C# */
00181         {  23, 150 },  /* *D  */
00182         {  22, 150 },  /* *D# */
00183         {  21, 150 },  /* *E  */
00184         {  19, 150 },  /* *F  */
00185         {  18, 150 },  /* *F# */
00186         {  17, 150 },  /* *G  */
00187         {  16, 150 },  /* *G# */
00188         {   0,   0 },  /* *R  */
00189     },
00190 };
00191 
00192 
00193 /* name table of notes */
00194 #ifdef UNIT_MSG
00195 static const char *note_name[MAXNOTE] = {
00196     "A",
00197     "A#",
00198     "B",
00199     "C",
00200     "C#",
00201     "D",
00202     "D#",
00203     "E",
00204     "F",
00205     "F#",
00206     "G",
00207     "G#",
00208     "R",
00209 };
00210 #endif /*UNIT_MSG*/
00211 
00212 
00213 /******************************************************************************
00214 * Function Name: piano4int_start
00215 * Description  : Play the score thru sound generator.
00216 *              : This function receives the sound language,
00217 *              : and plays specified sound language.
00218 * Arguments    : const int8_t *scores  : score
00219 *              : PIANO4INT_CB callback : callback function
00220 * Return Value : none
00221 ******************************************************************************/
00222 void piano4int_start(const int8_t *scores[SDG_CH_TOTAL], PIANO4INT_CB callback)
00223 {
00224     const int8_t    *score;     /* pointer to score */
00225     uint16_t        speed;      /* sound speed */
00226     int32_t         ch;         /* channel no */
00227     int32_t         ret;        /* function result */
00228 
00229     /* prepare for playing the score */
00230     for (ch = 0; ch < SDG_CH_TOTAL; ch++) {
00231         if (scores[ch] == NULL) {
00232             /* score is not specified */
00233             pianoT.unit[ch].score = noscore;
00234             pianoT.unit[ch].top   = noscore;
00235         } else {
00236             /* prepare for playing a score */
00237             score = scores[ch];
00238 
00239             /* get the speed */
00240             speed = 0;
00241             while (isdigit(*score)) {
00242                 speed = (speed * 10) + ((*score++) - '0');
00243             }
00244             if (0 == speed) {
00245                 /* can not play the score */
00246                 printf("speed[%d]:%d, can not play, there is no speed information.\n", (int)ch, speed);
00247                 return;
00248             } else {
00249                 printf("speed[%d]:%d\n", (int)ch, speed);
00250                 /* calculate a base speed for ticker */
00251                 pianoT.unit[ch].speed = BASESPEED / speed;
00252 
00253                 /* default loudness (unsupported to change) */
00254                 pianoT.unit[ch].loudness = DEFLOUDNESS;
00255 
00256                 /* set top of a score */
00257                 pianoT.unit[ch].top   = score;
00258                 pianoT.unit[ch].score = score;
00259 
00260                 /* play no sounds */
00261                 pianoT.unit[ch].count = 0;
00262 
00263                 /* rest4 */
00264                 pianoT.unit[ch].note = rest4;
00265 
00266                 /* channel number */
00267                 pianoT.unit[ch].channel = unitHW[ch].channel;
00268 
00269 #ifdef  UNIT_MSG
00270                 /* message */
00271                 pianoT.unit[ch].msg[0] = '\0';
00272 #endif
00273 
00274                 /* Initialize Sound Generator */
00275                 ret = R_SDG_Open(unitHW[ch].channel, unitHW[ch].clock);
00276                 ASSERT(0 == ret);
00277             }
00278         }
00279     }
00280 
00281     /* set callback function */
00282     pianoT.callback = callback;
00283 
00284     /* clear flags to finish playing */
00285     pianoT.fin = 0;
00286 
00287     /* start the metronome  (unit: 1ms) */
00288     pianoT.metronome.attach_us(&play_score, 1000.0);
00289 }
00290 
00291 /******************************************************************************
00292 * Function Name: piano4int_stop
00293 * Description  : Stop the sounds through sound generator.
00294 * Arguments    : bool force : flag to stop forcedly (now, ignored)
00295 * Return Value : none
00296 ******************************************************************************/
00297 void piano4int_stop(bool force)
00298 {
00299     int32_t         ch;
00300     int32_t         ret;
00301 
00302     /* wait until sounds stop */
00303     do {
00304         /* wait 10.0 sec */
00305         wait_us(10.0 * 1000.0);
00306 #ifdef UNIT_MSG
00307         for (ch = 0; ch < SDG_CH_TOTAL; ch++) {
00308             if ('\0' != pianoT.unit[ch].msg[0]) {
00309                 printf(&pianoT.unit[ch].msg[0]);
00310                 pianoT.unit[ch].msg[0] = '\0';
00311             }
00312         }
00313 #endif /*UNIT_MSG*/
00314     } while (pianoT.fin != ((1 << SDG_CH_TOTAL) - 1));
00315     /* all scores finished */
00316 
00317     /* stops the metronome */
00318     pianoT.metronome.detach();
00319 
00320     /* stop all sound generators */
00321     for (ch = 0; ch < SDG_CH_TOTAL; ch++) {
00322         if (pianoT.unit[ch].top != noscore) {
00323             /* stop sound generator */
00324             ret = R_SDG_Close(unitHW[ch].channel);
00325             ASSERT(0 == ret);
00326         }
00327     }
00328 }
00329 
00330 /******************************************************************************
00331 * Function Name: piano4int_status
00332 * Description  : Get the flag to finish playing the score
00333 * Arguments    : none
00334 * Return Value : The flag
00335 * Note         : Output the comment if the macro "UNIT_MSG" is defined
00336 ******************************************************************************/
00337 bool piano4int_status(void)
00338 {
00339 #ifdef UNIT_MSG
00340     int32_t ch;
00341 
00342     /* output the comments from interrupts */
00343     for (ch = 0; ch < SDG_CH_TOTAL; ch++) {
00344         if ('\0' != pianoT.unit[ch].msg[0]) {
00345             printf(&pianoT.unit[ch].msg[0]);
00346             pianoT.unit[ch].msg[0] = '\0';
00347         }
00348     }
00349 #endif
00350 
00351     return (pianoT.fin != ((1 << SDG_CH_TOTAL) - 1));
00352 }
00353 
00354 
00355 /******************************************************************************
00356 * Function Name: play_score
00357 * Description  : Play the score on interrupt
00358 * Arguments    : none
00359 * Return Value : none
00360 ******************************************************************************/
00361 void play_score(void)
00362 {
00363     UNIT            *unit;
00364     const int8_t    *score;
00365     uint16_t        octave;
00366     uint16_t        key;
00367     uint16_t        pitch;
00368     uint16_t        dot;
00369     uint16_t        tie;
00370     uint8_t         loud;
00371     uint16_t        duration;
00372     uint16_t        value;
00373     uint16_t        ch;
00374     bool            err;
00375 
00376     for (ch = 0; ch < SDG_CH_TOTAL; ch++) {
00377         /* Check finish flag */
00378         if (0 != (pianoT.fin & (1 << ch))) {
00379             continue;   /* finish */
00380         }
00381 
00382         if (0 == pianoT.unit[ch].count) {
00383             unit    = &pianoT.unit[ch];
00384             score   = unit->score;
00385 
00386             if ('\0' == *score) {
00387                 /* set finish flag */
00388                 pianoT.fin |= (1 << ch);
00389                 continue;
00390             }
00391 
00392             /* Initialize parameters */
00393             octave  = 0;
00394             key     = 0;
00395             pitch   = 0;
00396             dot     = 0;
00397             tie     = 0;
00398             err     = false;
00399 
00400             /* skip some spaces */
00401             while (' ' == *score) {
00402                 score++;
00403             }
00404 
00405             /* octave */
00406             switch (*score) {
00407                 case OCTAVE0_CHAR:  { octave = OCTAVE_LEVEL_0; score++; break; }
00408                 case OCTAVE1_CHAR:  { octave = OCTAVE_LEVEL_1; score++; break; }
00409                 case OCTAVE2_CHAR:  { octave = OCTAVE_LEVEL_2; score++; break; }
00410                 case OCTAVE3_CHAR:  { octave = OCTAVE_LEVEL_3; score++; break; }
00411                 default:            { octave = OCTAVE_LEVEL_1;          break; }
00412             }
00413 
00414             /* key */
00415             switch (toupper(*score)) {
00416                 case NOTE_DO_CHAR:  { key = KEY_C; score++; break; }
00417                 case NOTE_RE_CHAR:  { key = KEY_D; score++; break; }
00418                 case NOTE_MI_CHAR:  { key = KEY_E; score++; break; }
00419                 case NOTE_FA_CHAR:  { key = KEY_F; score++; break; }
00420                 case NOTE_SO_CHAR:  { key = KEY_G; score++; break; }
00421                 case NOTE_RA_CHAR:  { key = KEY_A; score++; break; }
00422                 case NOTE_SI_CHAR:  { key = KEY_B; score++; break; }
00423                 case NOTE_REST_CHAR:{ key = KEY_R; score++; break; }
00424                 default:
00425                     err = true;
00426             }
00427 
00428             if (((KEY_A == key) && (OCTAVE_LEVEL_0 == octave)) ||
00429                 ((KEY_B == key) && (OCTAVE_LEVEL_0 == octave))) {
00430                 err = true;
00431             }
00432 
00433             /* sharp */
00434             if (NOTE_SHARP == (*score)) {
00435                 if (KEY_R == key) {
00436                     err = true;
00437                 } else {
00438                     key++;
00439                     score++;
00440                 }
00441             }
00442 
00443             /* pitch */
00444             if (isdigit(*score)) {
00445                 pitch = ((*score++) - '0');
00446                 if (isdigit(*score)) {
00447                     pitch = (pitch * 10) + ((*score++) - '0');
00448                 }
00449             } else {
00450                 err = true;
00451             }
00452 
00453             /* dotted */
00454             if (NOTE_DOT == (*score)) {
00455                 dot = DOTTED_NOTE;
00456                 score++;
00457             } else {
00458                 dot = NOT_DOTTED_NONE;
00459             }
00460 
00461             /* tie */
00462             if (NOTE_TIE == (*score)) {
00463                 tie = TIED_NOTE;
00464                 score++;
00465             } else {
00466                 tie = NOT_TIED_NONE;
00467             }
00468 
00469             /* set score */
00470             unit->score = score;
00471 
00472 #ifdef  UNIT_MSG
00473             snprintf(&unit->msg[0], UNIT_MSG - 1, "%d)%d%s%d -> %d/%d/%d\n",
00474                 unit->channel,
00475                 octave,
00476                 note_name[key],
00477                 pitch,
00478                 note_timing[octave][key].tone,
00479                 note_timing[octave][key].sfs,
00480                 unit->speed / pitch);
00481 #endif /* UNIT_MSG */
00482 
00483             if (!err) {
00484                 /* set the sound volume */
00485                 loud     = (0 == note_timing[octave][key].sfs) ? (0): (unit->loudness);
00486                 /* set */
00487                 duration = unit->speed / pitch;
00488                 if (dot) {
00489                     duration += (duration >> 1);
00490                 }
00491 
00492                 /* set next note or rest */
00493                 unit->note.tone         = note_timing[octave][key].tone;
00494                 unit->note.sfs          = note_timing[octave][key].sfs;
00495                 unit->note.loud         = loud;
00496                 unit->note.attenuation  = tie;
00497 
00498                 R_SDG_Tone(pianoT.unit[ch].channel, &pianoT.unit[ch].note);
00499                 pianoT.unit[ch].count = duration;
00500             } else {
00501                 pianoT.fin |= (1 << ch);
00502             }
00503 
00504             /* marker */
00505             if (NOTE_MARKER == (*score)) {
00506                 score++;
00507                 value = 0;
00508                 if (isdigit(*score)) {
00509                     value = ((*score++) - '0');
00510                     if (isdigit(*score)) {
00511                         value = (value * 10) + ((*score++) - '0');
00512                     }
00513                 }
00514                 unit->score = score;
00515 
00516                 if (NULL != pianoT.callback) {
00517                     pianoT.callback(pianoT.unit[ch].channel, value);
00518                 }
00519             }
00520         } else {
00521             pianoT.unit[ch].count--;
00522         }
00523     }
00524 }
00525 
00526 /* End of File */