mybin

my ~/bin
git clone https://a3nm.net/git/mybin/
Log | Files | Refs | README

a2freq.c (2872B)


      1 /* a2freq - convert MIDI note numbers or scientific pitch notations to frequencies */
      2 /* by Antoine Amarilli (2011) */
      3 /* licence: public domain */
      4 /* compilation: cc -o a2freq a2freq.c -lm */
      5 
      6 #include <stdio.h>
      7 #include <math.h>
      8 #include <ctype.h>
      9 
     10 #define E_ARGS 1
     11 #define E_PARSE 2
     12 
     13 int atoi(const char *nptr);
     14 
     15 
     16 float key2freq(int n)
     17 {
     18   /* Return frequency of midi note number n, inspired by the "Piano key
     19    * frequencies" article on wikipedia */
     20 
     21   return 440*pow(2, ((float) (n - 69))/12);
     22 }
     23 
     24 
     25 int name2num(char name)
     26 {
     27   /* Return note number adjustment for upper case scientific pitch
     28    * notation note name name. Return <0 on error. */
     29 
     30   switch(name)
     31   {
     32     case 'C':
     33       return 0;
     34     case 'D':
     35       return 2;
     36     case 'E':
     37       return 4;
     38     case 'F':
     39       return 5;
     40     case 'G':
     41       return 7;
     42     case 'A':
     43       return 9;
     44     case 'B':
     45       return 11;
     46     default:
     47       return -1;
     48   }
     49 }
     50 
     51 
     52 int accid2num(char accid)
     53 {
     54   /* Return note number adjustment for scientific pitch notation note
     55    * accidental. Return 0 on error. */
     56 
     57   switch (accid) {
     58     case 'b':
     59       return -1;
     60     case '#':
     61       return 1;
     62     default:
     63       return 0;
     64   }
     65 }
     66 
     67 
     68 int note2num(int octave, int note)
     69 {
     70   /* Return MIDI note number for octave and note. */
     71 
     72   return (octave + 1)*12 + note;
     73 }
     74 
     75 
     76 float pitch2freq(char* a)
     77 {
     78   /* Return frequency of scientific pitch notation note a, by converting
     79    * it to a key number and using key2freq. Return <0 on parse error. */
     80  
     81   // octavepos position where octave indication is expected
     82   int note, octave = 4, accid, octavepos = 1;
     83 
     84   /* parse note name */
     85   if (!a[0]) return -1;
     86   note = name2num(toupper(a[0]));
     87   if (note < 0) return note;
     88   
     89   /* parse accidental */
     90   if (a[octavepos] && !isdigit(a[octavepos])) {
     91     accid = accid2num(a[octavepos]);
     92     if (!accid) return -1;
     93     note += accid;
     94     octavepos++;
     95   }
     96 
     97   /* parse octave */
     98   return key2freq(!a[octavepos]?
     99       note2num(octave, note):
    100       note2num(atoi(a + octavepos), note));
    101 }
    102 
    103 
    104 float do_one(char* a)
    105 {
    106   int result;
    107 
    108   if ((result = atoi(a)))
    109     return key2freq(result);
    110   else return pitch2freq(a);
    111 }
    112 
    113 
    114 int main(int argc, char** argv)
    115 {
    116   int i;
    117   double result;
    118 
    119   if (argc <= 1) {
    120     fprintf(stderr,
    121         "Usage: %s [NOTE]...\n", argv[0]);
    122     fprintf(stderr,
    123         "Convert MIDI note numbers or scientific pitch notations to "
    124         "frequencies.\n");
    125     fprintf(stderr,
    126         "NOTE is either a MIDI note number or a key in scientific pitch "
    127         "notation.\n");
    128     fprintf(stderr,
    129         "Scientific pitch notation examples: \"A4\", \"C#2\", " "\"Bb6\"\n");
    130     return E_ARGS;
    131   }
    132       
    133   for (i=1; i<argc; i++)
    134   {
    135     result = do_one(argv[i]);
    136     if (result >= 0)
    137       printf("%f\n", result);
    138     else {
    139       fprintf(stderr, "a2freq: cannot parse %s\n", argv[i]);
    140       return E_PARSE;
    141     }
    142   }
    143 
    144   return 0;
    145 }
    146