Code covered by the BSD License  

Highlights from
xPC Target Driver Authoring Tool Tutorial

image thumbnail

xPC Target Driver Authoring Tool Tutorial

by

 

23 Jun 2008 (Updated )

A step-by-step tutorial on how to create custom device drivers for xPC Target using xpcdrivertool.

...
function [frequencies, durations, error, statistics] = ...
   song(notes, tempo, key, steps, octaves, tune)
% SONG converts a simple text based musical note notation
%      to frequencies & durations.
%
%   SONG takes up to 6 input arguments.
%      notes   - A space delimited string of musical notes.
%      tempo   - The tempo of the song in beats per minute.
%      key     - A key signature.
%      steps   - Number of steps to raise or lower each note.
%      octaves - Number of octaves to raise or lower every note.
%      tune    - Shift notes up or down.
%   SONG returns up to 4 arguments.
%      frequencies - A vector of frequencies for each note.
%      duration    - A vector of time durations for each note.
%      error       - A message indicating any error.
%                    An empty string if no errors detected.
%      statistics  - A vector containing statistics for the song.
%                    [Length Notes Min Max]
%                    Length - Length of the song in seconds.
%                    Notes  - Number of notes in the song.
%                    Min    - Lowest non-zero frequency in the song.
%                    Max    - Highest frequency in the song.
%
%   The format for the NOTES is as follows:
%      [octave]note[[#]accidental][beats]
%   Where:
%      octave     - A number specifying the octave. Default is 0.
%                   0 represents the octave of middle C.
%      note       - A letter in the range A-G (and R or Z for a rest),
%                   that specifies the specific note.
%                   No default, the note must be specified.
%      accidental - One of n, b or #, to indicate natural, flat, or sharp.
%                   Default is n, natural.
%                   Each accidental applies to one note only, and
%                   completely overrides the key signature for that note.
%                   A number can optionally proceed the accidental
%                   to indicate multiple or fractional sharps and flats.
%                   Default is 1.
%      beats      - A number greater than zero to indicate length of the
%                   note in beats. Default is 1.
%   Each note must be seperated by a space.
%
%   There are two formats for TEMPO as follows:
%      The number of beats per minute. Default is 90.
%      The tempo can be specified by name.
%      The following names are recognized using the following tempos:
%         'Prestissimo' = 200      'Andante'     = 90
%         'Vivacissimo' = 190      'Adagietto'   = 75
%         'Presto'      = 180      'Adagio'      = 70
%         'Vivace'      = 140      'Larghetto'   = 60
%         'Allegro'     = 130      'Lento'       = 50
%         'Allegretto'  = 120      'Largamente'  = 40
%         'Moderato'    = 110      'Larghissimo' = 20
%
%   There are two formats for the KEY signature as follows:
%      A comma delimited string of characters. Each letter can be either
%         n, f or s to indicate natural, flat or sharp. The order of the
%         notes is C,D,E,F,G,A,B.
%      The key signature can be specified by name.
%      The following names are recognized:
%         'C' &'Aminor'  ='n,n,n,n,n,n,n'
%         'G' &'Eminor'  ='n,n,n,s,n,n,n'   'F' &'Dminor'  ='n,n,n,n,n,n,f'
%         'D' &'Bminor'  ='s,n,n,s,n,n,n'   'Bb'&'Gminor'  ='n,n,f,n,n,n,f'
%         'A' &'F#minor' ='s,n,n,s,s,n,n'   'Eb'&'Cminor'  ='n,n,f,n,n,f,f'
%         'E' &'C#minor' ='s,s,n,s,s,n,n'   'Ab'&'Fminor'  ='n,f,f,n,n,f,f'
%         'B' &'G#minor' ='s,s,n,s,s,s,n'   'Db'&'Bbminor' ='n,f,f,n,f,f,f'
%         'F#'&'D#minor' ='s,s,s,s,s,s,n'   'Gb'&'Ebminor' ='f,f,f,n,f,f,f'
%         'C#'&'A#minor' ='s,s,s,s,s,s,s'   'Cb'&'Abminor' ='f,f,f,f,f,f,f'
%         'Aharmonic'  ='n, n,n,n,s,n,n'
%         'Eharmonic'  ='n,s,n,s,n,n,n'    'Dharmonic'  ='s,n,n,n,n,n,f'
%         'Bharmonic'  ='s,n,n,s,n,s,n'    'Gharmonic'  ='n,n,f,s,n,n,f'
%         'F#harmonic' ='s,n,s,s,s,n,n'    'Charmonic'  ='n,n,f,n,n,f,n'
%         'C#harmonic' ='s,s,n,s,s,n,s'    'Fharmonic'  ='n,f,n,n,n,f,f'
%         'G#harmonic' ='s,s,n,2s,s,s,n'   'Bbharmonic' ='n,f,f,n,f,n,f'
%         'D#harmonic' ='2s,s,s,s,s,s,n'   'Ebharmonic' ='f,n,f,n,f,f,f'
%         'A#harmonic' ='s,s,s,s,2s,s,s'   'Abharmonic' ='f,f,f,f,n,f,f'
%   Default is the C major key.
%
%   Each note can be raised or lowered a specified number of STEPS.
%   Each step equals two semitones. Default is 0.
%
%   The entire piece can be shifted up or down full or fractional OCTAVES.
%   Default is 0, no shift.
%
%   The TUNE of the entire song can be modified. The A above middle C is
%   defined as 440Hz. This can be adjusted to any frequency, by shifting
%   A4 up or down the specified number of Hz. Default is 0.
%
%   Example:
%      [sng.tune, sng.rhythm, sng.message, sng.stats] = ...
%      song('c d e f g a b 1c2 r 1c b a g f e d c4','Allegro','C',0,0,0);
%
%   song - version 1.0      Jon Raichek      jraichek@mathworks.com

   frequencies = [];
   durations   = [];
   error       = '';
   statistics  = [0 0 0 0];

   middleC  = 0.0;
   A4       = 440.0;
   r12      = power(2.0, 1.0/12.0);
   AoffsetC = 9.0;

   % Set default tune & A4
   if nargin < 6
      tune = 0.0;
   end
   if ~isnumeric(tune)
      error = ['Tune "' tune '" must be a number.'];
      return
   end
   A4 = A4 + tune;

   % Set default octave
   if nargin < 5
      octaves = 0.0;
   end
   if ~isnumeric(octaves)
      error = ['Octave "' octaves '" must be a number.'];
      return
   end
   octaves = octaves - middleC;

   % Set default steps & semitones
   if nargin < 4
      steps = 0.0;
   end
   if ~isnumeric(steps)
      error = ['Steps "' steps '" must be a number.'];
      return
   end
   semiTones = steps * 2.0;

   % Set default key signature
   if nargin < 3
      key = 'C';
   end
   if ~ischar(key)
      error = ['Key "' num2str(key) '" must be a string.'];
      return
   end

   % Set default tempo & SPB
   if nargin < 2
      tempo = 90.0;
   else
      if ischar(tempo)
         tempo = lower(tempo);
         switch tempo
            case 'prestissimo'
               tempo = 200;
            case 'vivacissimo'
               tempo = 190;
            case 'presto'
               tempo = 180;
            case 'vivace'
               tempo = 140;
            case 'allegro'
               tempo = 130;
            case 'allegretto'
               tempo = 120;
            case 'moderato'
               tempo = 110;
            case 'andante'
               tempo =  90;
            case 'adagietto'
               tempo =  75;
            case 'adagio'
               tempo =  70;
            case 'larghetto'
               tempo =  60;
            case 'lento'
               tempo =  50;
            case 'largamente'
               tempo =  40;
            case 'larghissimo'
               tempo =  20;
            otherwise
               error = ['I do not know the tempo "' tempo, '"'];
               tempo = 90.0;
         end
      end
   end
   secondsPerBeat = 60.0 / tempo;
   if 0 > secondsPerBeat
      error = ['The tempo "' num2str(tempo) '" is too slow.'];
      secondsPerBeat = 60.0 / 90.0;
   end

   % Check notes
   if nargin < 1
      error = 'I will pick a song for you.';
      [notes, ferror] = local_pickSong(-1);
      if ferror
         error = ferror;
      end
   end
   if isnumeric(notes)
      [notes, ferror] = local_pickSong(notes);
      if ferror
         error = ferror;
      end
   else
      if strcmp(notes, 'random')
         [notes, ferror] = local_pickSong(-1);
         if ferror
            error = ferror;
         end
      end
   end
   switch notes
      case 'twinkle'
         notes = ['c c g g a a g2 f f e e d d c2 g g f f e e d2 g g f ' ...
                 ' f e e d2 c c g g a a g2 f f e e d d c2             '];
      case 'jingle'
         notes = ['g.5 g.5 g 1e 1d 1c g3 g.5 g.5 g 1e 1d 1c a3 z.5 a.5' ...
                 ' b 1f 1e 1d b3 z.5 b.5 1g 1g 1f 1d 1e3 g.5 g.5 g 1e ' ...
                 ' 1d 1c g3 g.5 g.5 g 1e 1d 1c a3 z.5 a.4 b 1f 1e 1d  ' ...
                 ' 1g 1g 1g1.5 1g.5 1a 1g 1f 1d 1c3 1g 1e 1e 1e2 1e 1e' ...
                 ' 1e2 1e 1g 1c1.5 1d.5 1e3 z 1f 1f 1f1.5 1f.5 1f 1e  ' ...
                 ' 1e 1e.5 1e.5 1e 1d 1d 1e 1d2 1g2 1e 1e 1e2 1e 1e   ' ...
                 ' 1e2 1e 1g 1c1.5 1d.5 1e3 z.5 1f 1f 1f1.5 1f.5 1f 1e' ...
                 ' 1e 1e.5 1e.5 1g 1g 1f 1d 1c3                       '];
      case 'b5intro'
         notes =  'z.5 g.5 g.5 g.5 eb2 z.5 f.5 f.5 f.5 d4             ' ;
   end

   % Lookup standard key signatures
   scale = '';
   key = lower(key);
   switch key
      case {'cmajor', 'cmaj', 'c'}
         key = 'n n n n n n n';
         scale = ['c d e f g a b 1c2 r' ...
                 ' 1c b a g f e d c4'];
      case {'gmajor', 'gmaj', 'g'}
         key = 'n n n s n n n';
         scale = ['g a b 1c 1d 1e 1f# 1g2 r' ...
                 ' 1g 1f# 1e 1d 1c b a g4'];
      case {'dmajor', 'dmaj', 'd'}
         key = 's n n s n n n';
         scale = ['d e f# g a b 1c# 1d2 r' ...
                 ' 1d 1c# b a g f# e d4'];
      case {'amajor', 'amaj', 'a'}
         key = 's n n s s n n';
         scale = ['a b 1c# 1d 1e 1f# 1g# 1a2 r' ...
                 ' 1a 1g# 1f# 1e 1d 1c# b a4'];
      case {'emajor', 'emaj', 'e'}
         key = 's s n s s n n';
         scale = ['e f# g# a b 1c# 1d# 1e2 r' ...
                 ' 1e 1d# 1c# b a g# f# e4'];
      case {'bmajor', 'bmaj', 'b'}
         key = 's s n s s s n';
         scale = ['b 1c# 1d# 1e 1f# 1g# 1a# 1b2 r' ...
                 ' 1b 1a# 1g# 1f# 1e 1d# 1c# b4'];
      case {'f#major', 'f#maj', 'f#'}
         key = 's s s s s s n';
         scale = ['f# g# a# b 1c# 1d# 1e# 1f#2 r' ...
                 ' 1f# 1e# 1d# 1c# b a# g# f#4'];
      case {'c#major', 'c#maj', 'c#'}
         key = 's s s s s s s';
         scale = ['c# d# e# f# g# a# b# 1c#2 r' ...
                 ' 1c# b# a# g# f# e# d# c#4'];
      case {'fmajor', 'fmaj', 'f'}
         key = 'n n n n n n f';
         scale = ['f g a bb 1c 1d 1e 1f2 r' ...
                 ' 1f 1e 1d 1c bb a g f4'];
      case {'bbmajor', bbmaj', 'bb'}
         key = 'n n f n n n f';
         scale = ['bb 1c 1d 1eb 1f 1g 1a 1bb2 r' ...
                 ' 1bb 1a 1g 1f 1eb 1d 1c bb4'];
      case {'ebmajor', 'ebmaj', 'eb'}
         key = 'n n f n n f f';
         scale = ['eb f g ab bb 1c 1d 1eb2 r' ...
                 ' 1eb 1d 1c bb ab g f eb4'];
      case {'abmajor', 'abmaj', 'ab'}
         key = 'n f f n n f f';
         scale = ['ab bb 1c 1db 1eb 1f 1g 1ab2 r' ...
                 ' 1ab 1g 1f 1eb 1db 1c bb ab4'];
      case {'dbmajor', 'dbmaj', 'db'}
         key = 'n f f n f f f';
         scale = ['db eb f gb ab bb 1c 1db2 r' ...
                 ' 1db 1c bb ab gb f eb db4'];
      case {'gbmajor', 'gbmaj', 'gb'}
         key = 'f f f n f f f';
         scale = ['gb ab bb 1cb 1db 1eb 1f 1gb2 r' ...
                 ' 1gb 1f 1eb 1db 1cb bb ab gb4'];
      case {'cbmajor', 'cbmaj', 'cb'}
         key = 'f f f f f f f';
         scale = ['cb db eb fb gb ab bb 1cb2 r' ...
                 ' 1cb bb ab gb fb eb db cb4'];
      case {'aminor', 'amin', 'am'}
         key = 'n n n n n n n';
         scale = ['a b 1c 1d 1e 1f 1g 1a2 r' ...
                 ' 1a 1g 1f 1e 1d 1c b a4'];
      case {'eminor', 'emin', 'em'}
         key = 'n n n s n n n';
         scale = ['e f# g a b 1c 1d 1e2 r' ...
                 ' 1e 1d 1c b a g f# e4'];
      case {'bminor', 'bmin', 'bm'}
         key = 's n n s n n n';
         scale = ['b 1c# 1d 1e 1f# 1g 1a 1b2 r' ...
                 ' 1b 1a 1g 1f# 1e 1d 1c# b4'];
      case {'f#minor', 'f#min', 'f#m'}
         key = 's n n s s n n';
         scale = ['f# g# a b 1c# 1d 1e 1f#2 r' ...
                 ' 1f# 1e 1d 1c# b a g# f#4'];
      case {'c#minor', 'c#min', 'c#m'}
         key = 's s n s s n n';
         scale = ['c# d# e f# g# a b 1c#2 r' ...
                 ' 1c# b a g# f# e d# c#4'];
      case {'g#minor', 'g#min', 'g#m'}
         key = 's s n s s s n';
         scale = ['g# a# b 1c# 1d# 1e 1f# 1g#2 r' ...
                 ' 1g# 1f# 1e 1d# 1c# b a# g#4'];
      case {'d#minor', 'd#min', 'd#m'}
         key = 's s s s s s n';
         scale = ['d# e# f# g# a# b 1c# 1d#2 r' ...
                 ' 1d# 1c# b a# g# f# e# d#4'];
      case {'a#minor', 'a#min', 'a#m'}
         key = 's s s s s s s';
         scale = ['a# b# 1c# 1d# 1e# 1f# 1g# 1a#2 r' ...
                 ' 1a# 1g# 1f# 1e# 1d# 1c# b# a#4'];
      case {'dminor', 'dmin', 'dm'}
         key = 'n n n n n n f';
         scale = ['d e f g a bb 1c 1d2 r' ...
                 ' 1d 1c bb a g f e d4'];
      case {'gminor', 'gmin', 'gm'}
         key = 'n n f n n n f';
         scale = ['g a bb 1c 1d 1eb 1f 1g2 r' ...
                 ' 1g 1f 1eb 1d 1c bb a g4'];
      case {'cminor', 'cmin', 'cm'}
         key = 'n n f n n f f';
         scale = ['c 1d 1eb 1f 1g 1ab 1bb 1c2 r' ...
                 ' 1c 1bb 1ab 1g 1f 1eb 1d c4'];
      case {'fminor', 'fmin', 'fm'}
         key = 'n f f n n f f';
         scale = ['f g ab bb 1c 1db 1eb 1f2 r' ...
                 ' 1f 1eb 1db 1c bb ab g f4'];
      case {'bbminor', 'bbmin', 'bbm'}
         key = 'n f f n f f f';
         scale = ['bb 1c 1db 1eb 1f 1gb 1ab 1bb2 r' ...
                 ' 1bb 1ab 1gb 1f 1eb 1db 1c bb4'];
      case {'ebminor', 'ebmin', 'ebm'}
         key = 'f f f n f f f';
         scale = ['eb f gb ab bb 1cb 1db 1eb2 r' ...
                 ' 1eb 1db 1cb bb ab gb f eb4'];
      case {'abminor', 'abmin', 'abm'}
         key = 'f f f f f f f';
         scale = ['ab bb 1cb 1db 1eb 1fb 1gb 1ab2 r' ...
                 ' 1ab 1gb 1fb 1eb 1db 1cb bb ab4'];
      case {'aharmonic' 'aharm' 'ah'}
         key = ' n  n  n  n  s  n  n';
         scale = ['a b 1c 1d 1e 1f 1g# 1a2 r' ...
                 ' 1a 1g# 1f 1e 1d 1c b a4'];
      case {'eharmonic' 'eharm' 'eh'}
         key = ' n  s  n  s  n  n  n';
         scale = ['e f# g a b 1c 1d# 1e2 r' ...
                 ' 1e 1d# 1c b a g f# e4'];
      case {'bharmonic' 'bharm' 'bh'}
         key = ' s  n  n  s  n  s  n';
         scale = ['b 1c# 1d 1e 1f# 1g 1a# 1b2 r' ...
                 ' 1b 1a# 1g 1f# 1e 1d 1c# b4'];
      case {'f#harmonic' 'f#harm' 'f#h'}
         key = ' s  n  s  s  s  n  n';
         scale = ['f# g# a b 1c# 1d 1e# 1f#2 r' ...
                 ' 1f# 1e# 1d 1c# b a g# f#4'];
      case {'c#harmonic' 'c#harm' 'c#h'}
         key = ' s  s  n  s  s  n  s';
         scale = ['c# d# e f# g# a b# 1c#2 r' ...
                 ' 1c# b# a g# f# e d# c#4'];
      case {'g#harmonic' 'g#harm' 'g#h'}
         key = ' s  s  n 2s  s  s  n';
         scale = ['g# a# b 1c# 1d# 1e 1f2# 1g#2 r' ...
                 ' 1g# 1f2# 1e 1d# 1c# b a# g#4'];
      case {'d#harmonic' 'd#harm' 'd#h'}
         key = '2s  s  s  s  s  s  n';
         scale = ['d# e# f# g# a# b 1c2# 1d#2 r' ...
                 ' 1d# 1c2# b a# g# f# e# d#4'];
      case {'a#harmonic' 'a#harm' 'a#h'}
         key = ' s  s  s  s 2s  s  s';
         scale = ['a# b# 1c# 1d# 1e# 1f# 1g2# 1a#2 r' ...
                 ' 1a# 1g2# 1f# 1e# 1d# 1c# b# a#4'];
      case {'dharmonic' 'dharm' 'dh'}
         key = ' s  n  n  n  n  n  f';
         scale = ['d e f g a bb 1c# 1d2 r' ...
                 ' 1d 1c# bb a g f e d4'];
      case {'gharmonic' 'gharm' 'gh'}
         key = ' n  n  f  s  n  n  f';
         scale = ['g a bb 1c 1d 1eb 1f# 1g2 r' ...
                 ' 1g 1f# 1eb 1d 1c bb a g4'];
      case {'charmonic' 'charm' 'ch'}
         key = ' n  n  f  n  n  f  n';
         scale = ['c 1d 1eb 1f 1g 1ab 1bn 1c2 r' ...
                 ' 1c 1bn 1ab 1g 1f 1eb 1d c4'];
      case {'fharmonic' 'fharm' 'fh'}
         key = ' n  f  n  n  n  f  f';
         scale = ['f g ab bb 1c 1db 1en 1f2 r' ...
                 ' 1f 1en 1db 1c bb ab g f4'];
      case {'bbharmonic' 'bbharm' 'bbh'}
         key = ' n  f  f  n  f  n  f';
         scale = ['bb 1c 1db 1eb 1f 1gb 1an 1bb2 r' ...
                 ' 1bb 1an 1gb 1f 1eb 1db 1c bb4'];
      case {'ebharmonic' 'ebharm' 'ebh'}
         key = ' f  n  f  n  f  f  f';
         scale = ['eb f gb ab bb 1cb 1dn 1eb2 r' ...
                 ' 1eb 1dn 1cb bb ab gb f eb4'];
      case {'abharmonic' 'abharm' 'abh'}
         key = ' f  f  f  f  n  f  f';
         scale = ['ab bb 1cb 1db 1eb 1fb 1gn 1ab2 r' ...
                 ' 1ab 1gn 1fb 1eb 1db 1cb bb ab4'];
      otherwise
   end

   % Play a scale
   if strcmp(notes, 'scale')
      if isempty(scale)
         scale = 'c d e f g a b 1c 1c b a g f e d c';
      end
      notes = scale;
   end

   % Parse key signature
   cdr = strrep(key, ',', ' ');
   keySig = [0 0 0 0 0 0 0];
   currentToken = 0;
   while ~isempty(cdr)
      [car, cdr] = strtok(cdr); %#ok<STTOK>
      if isempty(car)
         break
      end
      currentToken = currentToken + 1;
      badNote = ['I am not familier with the key signature ' ...
                 num2str(currentToken) ' "' car '". '];
      if currentToken > 7
         break
      end
      index = 1;
      [modifier, isNumber, index, ferror] = local_getNumber(car, index);
      if ferror
         error = [badNote ferror];
         return
      end
      if ~isNumber
         modifier = 1.0;
      end
      [accidental, isAccidental, index, ferror] = ...
         local_getAccidental(car, index);
      if ferror
         error = [badNote ferror];
         return
      end
      if ~ isAccidental
         error = [badNote 'No accidental provided.'];
         return
      end
      keySig(currentToken) = accidental * modifier;
      if index <= length(car)
         error = [badNote 'Extra stuff at end.'];
         return
      end
   end

   % Parse notes
   cdr = notes;
   currentToken = 0;
   while ~isempty(cdr)
      [car, cdr] = strtok(cdr); %#ok<STTOK>
      if isempty(car)
         break
      end
      currentToken = currentToken + 1;
      index = 1;
      badNote = ['Note ' num2str(currentToken) ' "' car ...
                 '" is out of tune. '];
      switch car(1)
         case '%'
            continue
         case {'@', '$', '!'}
            error = [badNote 'Reserved.'];
            continue
      end
      [octave, isNumber, index, ferror] = local_getNumber(car, index);
      if ferror
         error = [badNote ferror];
         break
      end
      if ~isNumber
         octave = middleC;
      end
      [note, isNote, index, ferror] = local_getNote(car, index);
      if ferror
         error = [badNote ferror];
         break
      end
      note = note - AoffsetC;
      [number, isNumber, index, ferror] = local_getNumber(car, index);
      if ferror
         error = [badNote ferror];
         break
      end
      [accidental, isAccidental, index, ferror] = ...
         local_getAccidental(car, index);
      if ferror
         error = [badNote ferror];
         break
      end
      if isAccidental
         if isNumber
            accidental = accidental * number;
         end
         [beats, isNumber, index, ferror] = local_getNumber(car, index);
         if ferror
            error = [badNote ferror];
            break
         end
      else
         if isNote
            accidental = keySig(isNote);
         end
         beats = number;
      end
      if ~isNumber
         beats = 1.0;
      end
      if 0 >= beats
         error = [badNote 'That is a very short note.'];
         continue
      end
      if index <= length(car) && car(index) == '/'
         error = [badNote 'Reserved.'];
         while index <= length(car) 
            if car(index) == '%'
               break
            end
            index = index + 1;
         end
      end
      if index <= length(car) && car(index) ~= '%'
         error = [badNote 'Extra stuff at end of note.'];
      end
      if isNote
         frequency = power(r12, note+accidental+semiTones) * ...
                     A4 *                                    ...
                     power(2, octave+octaves);
      else
         frequency = 0.0;
      end
      duration = beats * secondsPerBeat;
      frequencies = [frequencies frequency]; %#ok<AGROW>
      durations   = [durations   duration]; %#ok<AGROW>
   end

   % Collect statistics
   statistics = [sum(durations) length(frequencies)];
   if isempty(nonzeros(frequencies))
      statistics = [statistics 0];
   else
      statistics = [statistics min(nonzeros(frequencies))];
   end
   if isempty(frequencies)
      statistics = [statistics 0];
   else
      statistics = [statistics max(frequencies)];
   end

return   % End of song()


function [number, isNumber, next, error] = ...
   local_getNumber(numberString, index)
% LOCAL_GETNUMBER extracts a number from a note.
%
%   number   - The Number.
%   isNumber - 0: The was no number, 1: There was a number
%   next     - Index to first char after the number.
%   error    - Error message.

   number = 0.0;
   isNumber = 0;
   next = index;
   error = '';

   if length(numberString) < index
      return
   end

   % Number Format: [+|-]{0-9}[.]{0-9}

   sign = 1.0;
   if numberString(index) == '+'
      sign = 1.0;
      index = index + 1;
   elseif numberString(index) == '-'
      sign = -1.0;
      index = index + 1;
   end

   if length(numberString) < index
      error = 'Bad number, need more than a sign.';
      next = index;
      return
   end

   while numberString(index) == '0' || numberString(index) == '1' || ...
         numberString(index) == '2' || numberString(index) == '3' || ...
         numberString(index) == '4' || numberString(index) == '5' || ...
         numberString(index) == '6' || numberString(index) == '7' || ...
         numberString(index) == '8' || numberString(index) == '9'
      digit = 0;
      if numberString(index) == '1', digit = 1; end
      if numberString(index) == '2', digit = 2; end
      if numberString(index) == '3', digit = 3; end
      if numberString(index) == '4', digit = 4; end
      if numberString(index) == '5', digit = 5; end
      if numberString(index) == '6', digit = 6; end
      if numberString(index) == '7', digit = 7; end
      if numberString(index) == '8', digit = 8; end
      if numberString(index) == '9', digit = 9; end
      number = (number * 10) + digit;
      index = index + 1;
      if length(numberString) < index
         break;
      end
   end

   if length(numberString) < index
      next = index;
      number = number * sign;
      isNumber = 1;
      return
   end

   fraction = 0.1;
   if numberString(index) == '.'
      index = index + 1;
      if length(numberString) < index
         next = index;
         number = number * sign;
         isNumber = 1;
         return
      end
      while numberString(index) == '0' || numberString(index) == '1' || ...
            numberString(index) == '2' || numberString(index) == '3' || ...
            numberString(index) == '4' || numberString(index) == '5' || ...
            numberString(index) == '6' || numberString(index) == '7' || ...
            numberString(index) == '8' || numberString(index) == '9'
         digit = 0;
         if numberString(index) == '1', digit = 1; end
         if numberString(index) == '2', digit = 2; end
         if numberString(index) == '3', digit = 3; end
         if numberString(index) == '4', digit = 4; end
         if numberString(index) == '5', digit = 5; end
         if numberString(index) == '6', digit = 6; end
         if numberString(index) == '7', digit = 7; end
         if numberString(index) == '8', digit = 8; end
         if numberString(index) == '9', digit = 9; end
         number = number + (digit * fraction);
         fraction = fraction / 10.0;
         index = index + 1;
         if length(numberString) < index
            break;
         end
      end
   end

   next = index;

   number = number * sign;

   isNumber = 1;

return   % End of local_getNumber()


function [accidental, isAccidental, next, error] = ...
   local_getAccidental(accidentalString, index)
% LOCAL_GETACCIDENTAL extracts the accidental from a note.
%
%   accidental   - Number of semitones from the natural note.
%   isAccidental - 0: The was no accidental, 1: There was an accidental
%   next         - Index to first char after the accidental.
%   error        - Error message.

   accidental = 0.0;
   isAccidental = 0;
   next = index;
   error = '';

   if length(accidentalString) < index
      return
   end

   % accidental is the number of semitones from the natural note
   switch accidentalString(index)
      case {'n', 'N'}
         accidental = 0.0;
         isAccidental = 1;
      case {'b', 'f', 'F'}
         accidental = -1.0;
         isAccidental = 1;
      case {'#', 's', 'S'}
         accidental = 1.0;
         isAccidental = 1;
      otherwise
         accidental = 0.0;
         isAccidental = 0;
   end

   if isAccidental
      next = index + 1;
   end

return   % End of local_getAccidental()


function [note, isNote, next, error] = local_getNote(noteString, index)
% LOCAL_GETNOTE extracts the note.
%
%   note   - Number of semitones from C.
%   isNote - 0:Rest, 1:C, 2:D, 3:E, 4:F, 5:G, 6:A, 7:B
%   next   - Index to first char after the note.
%   error  - Error message.

   note = 0;
   isNote = 0;
   next = index;
   error = '';

   if length(noteString) < index
      error = 'There is no note.';
      return
   end

   % note is the number of semitones from C
   switch noteString(index)
      case {'A', 'a'}
         note = 9.0;
         isNote = 6;
      case {'B', 'b'}
         note = 11.0;
         isNote = 7;
      case {'C', 'c'}
         note = 0.0;
         isNote = 1;
      case {'D', 'd'}
         note = 2.0;
         isNote = 2;
      case {'E', 'e'}
         note = 4.0;
         isNote = 3;
      case {'F', 'f'}
         note = 5.0;
         isNote = 4;
      case {'G', 'g'}
         note = 7.0;
         isNote = 5;
      case {'R', 'r', 'Z', 'z'}
         isNote = 0;
      otherwise
         error = 'I only know the notes A-G and rests';
         return
   end

   next = index + 1;

return   % End of local_getNote()


function [ditty, error] = local_pickSong(pick)
% LOCAL_PICKSONG picks a song.
%
%   ditty - Name of selected or random song.
%   error - Error message.

   error = '';

   if pick < 0
      c = clock;
      pick = rem(round(c(6)*1000), 3);
   end

   switch pick
      case 0
         ditty = 'twinkle';
      case 1
         ditty = 'jingle';
      case 2
         ditty = 'b5intro';
      otherwise
         ditty = 'scale';
         error = 'I never heard of that song, how about a nice scale?';
   end

return   % End of local_pickSong()

Contact us