home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Subj: Guitarist's Helper
-
- Fellow guitarists/bassists:
-
- I wrote a program that prints a guitar fretboard diagram, and
- labels notes or patterns according command-line args. I found it
- helpful in learning and scales and patterns.
-
- The user can specify scale notes directly, or supply a root and
- formula for a scale. Positions on the fretboard diagram may be labled
- with a user-defined character if desired (this is good for learning
- patterns as opposed to actual note names). Here's a sample output:
-
- synapse /betty/b3/fcg 17> fretbd -i G# 2 2 1 2 2 2
-
- Scale = G# A# C C# D# F G
- + + + + + + + + + +
- -||-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|
- -||-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|
- G||-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|
- -||-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|
- -||-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|
- -||-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|
-
- This is my first posting of code to the net; any comments or
- suggestions are welcome. Please use e-mail replies where appropriate.
-
- - Yours truly
-
- */
- /* ********************************************************************** */
- /*
- * FILE: fretbd.2.c
- * AUTHOR: Frank C. Guida Philips Laboratories
- * (fcg@philabs.philips.com) Briarcliff Manor, NY 10510
- *
- * DATE: Fri Dec 22 10:49:29 1989
- *
- * Please acknowledge the author in any reproduction or modification.
- *
- * SYNOPSIS: fretbd [-h] [-s] [-m char]
- * [-i root interval_list] | [-n note_list]
- *
- * DESCRIPTION: fretbd prints a guitar fretboard (20 frets)
- * and labels notes according to the command-line
- * args. Notes may be entered in upper or lower
- * case; use b or # to indicate accidentals.
- *
- * OPTION SUMMARY: (no args): print blank fretboard.
- * -h: print this message.
- * -s: use sharps instead of flats as the
- * dflt_note_type (use with -i option).
- * -m: use char to mark note positions as
- * opposed to letter names.
- * -i: construct scale using specified root
- * and intervals (in half-steps).
- * -n: construct scale using specified notes.
- *
- * EXAMPLE: to print the F#maj scale -
- * host> fretbd -i F# 2 2 1 2 2 2
- *
- */
- /* ********************************************************************** */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
-
- #define HELP_MESSAGE "\
- Use: fretbd [-h] [-s] [-m char] [-i root interval_list] | [-n note_list]\n\n\
- Option Summary: (no args): print blank fretboard.\n\
- -h: print this message.\n\
- -s: use sharps instead of flats as the\n\
- dflt_note_type (use with -i option).\n\
- -m: use char to mark note positions as\n\
- opposed to letter names.\n\
- -i: construct scale using specified root\n\
- and intervals (in half-steps).\n\
- -n: construct scale using specified notes.\n"
-
- #define OP_HELP "-h"
- #define OP_SHARPS "-s"
- #define OP_POS_MARK "-m"
- #define OP_INTERVALS "-i"
- #define OP_NOTES "-n"
-
- #define NUM_FRETS 20 /* numbered 0-19 */
- #define NUM_STRINGS 6 /* numbered 1-6 */
- #define MAX_NOTES 12
-
- #define FLATS 0
- #define SHARPS 1
-
- #define NECK_INDEX "\
- + + + + + + +\
- + + +\n"
-
- /* Basic macros */
-
- #define streq(s1, s2) (strcmp(s1, s2) == 0)
-
- #define not_option(arg) !(streq(arg, OP_HELP) ||\
- streq(arg, OP_SHARPS) ||\
- streq(arg, OP_POS_MARK) ||\
- streq(arg, OP_INTERVALS) ||\
- streq(arg, OP_NOTES))
-
- /* function declarations */
-
- char *get_note();
- short note_index();
- void error();
- void print_fretbd();
- void print_note();
-
- /* global variables */
-
- static char *chrom[2][12] =
- { /* 1 2 3 4 5 6 7 */
- {"C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"},
- /* 0 1 2 3 4 5 6 7 8 9 10 11 */
- {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"}
- };
-
- char pos_mark_char = '\0';
- unsigned short note_type;
- unsigned short num_notes = 0;
-
- /* ********************************************************************** */
-
- main( argc, argv )
- int argc;
- char *argv[];
- {
- char *scale[MAX_NOTES];
- short note_idx;
- unsigned short a, i, interval;
- unsigned short dflt_note_type = FLATS;
-
- for( i=0; i < MAX_NOTES; i++ ) /* initialize scale array */
- scale[i] = "-";
-
- /* Parse and verify command-line args. Args are checked for
- * consistency with any associated option flag (i.e. if the -i option
- * is given, the following arg should be a valid note name, and
- * subsequent args should be valid intervals or a new option flag).
- */
-
- for( a=1; a < argc; a++ )
- {
- if( streq(argv[a], OP_HELP) )
- error( "", "" ); /* not really an error */
-
- else if( streq(argv[a], OP_SHARPS) )
- dflt_note_type = SHARPS;
-
- else if( streq(argv[a], OP_POS_MARK) )
- {
- if( (a+1 < argc) && not_option(argv[a+1]) )
- sscanf( argv[++a], "%c", &pos_mark_char );
- else
- error( "", "Specify one character for position mark." );
- }
- else if( streq(argv[a], OP_INTERVALS) )
- {
- i = 0;
- while( (a+1 < argc) && not_option(argv[a+1]) )
- {
- if( i == 0 ) /* first arg to -i option should be name of root */
- {
- /* convert case if needed */
-
- if( islower(*(argv[++a])) )
- *(argv[a]) = toupper( *(argv[a]) );
-
- if( (note_idx = note_index(argv[a])) >= 0 ) /* valid note? */
- {
- scale[i++] = chrom[note_type][note_idx];
-
- /* if root is an accidental, the scale should be */
- /* formed from the same note type, i.e. bs or #s */
-
- switch( note_idx )
- {
- case 1: case 3: case 6: case 8: case 10: /* accidentals */
- dflt_note_type = note_type;
- }
- }
- else
- error( argv[a], "is not a valid note!" );
- }
- else /* subsequent args to -i option should be intervals */
- {
- if( sscanf( argv[++a], "%hu", &interval ) == 1 )
- {
- /* determine new note_idx from last note_idx */
- note_idx = note_index(scale[i-1]) + (short)interval;
-
- while( note_idx > 11 ) /* correct any overflow */
- note_idx =- 12;
-
- scale[i++] = chrom[dflt_note_type][note_idx];
- }
- else
- error( argv[a], "is not a valid interval!" );
- }
- }
- num_notes = i;
- }
- else if( streq(argv[a], OP_NOTES) )
- {
- i = 0;
- while( (a+1 < argc) && not_option(argv[a+1]) )
- {
- /* convert case if needed */
-
- if( islower(*(argv[++a])) )
- *(argv[a]) = toupper( *(argv[a]) );
-
- if( note_index(argv[a]) >= 0 ) /* valid note? */
- scale[i++] = argv[a];
- else
- error( argv[a], "is not a valid note!" );
- }
- num_notes = i;
- }
- } /* end of argc loop */
-
- /* print scale */
-
- printf( "Scale =" );
- for( i=0; i < num_notes; i++ )
- printf( " %s", scale[i] );
- printf( " \n" );
-
- print_fretbd( scale );
-
- exit(0);
- }
-
- /* ********************************************************************** */
-
- void error( item, message )
- char *item, *message;
- /* Print error message, help message, and exit. */
- {
- fprintf( stderr," %s %s\n", item, message );
- fprintf( stderr, HELP_MESSAGE );
- exit(-1);
- }
-
-
- /* ********************************************************************** */
-
- short note_index( note )
- char *note;
- /* Returns the chromatic scale index of note and sets note_type
- * if note is an accidental; returns -1 if note is not a member
- * of the chromatic scale.
- */
- {
- short i;
-
- for( i=0; i < 12; i++ )
- {
- note_type = FLATS;
- if( streq(note, chrom[note_type][i]) )
- return(i);
- note_type = SHARPS;
- if( streq(note, chrom[note_type][i]) )
- return(i);
- }
- return(-1);
- }
-
- /* ********************************************************************** */
-
- void print_fretbd( scale )
- char *scale[];
- /* Print fretboard, labeling notes in scale[]. */
- {
- char *note;
- register unsigned short string, fret_idx, fret;
-
- printf( NECK_INDEX );
-
- for( string=1; string <= NUM_STRINGS; string++ )
- {
- switch( string )
- {
- case 2: fret_idx = 11; break; /* B */
- case 3: fret_idx = 7; break; /* G */
- case 4: fret_idx = 2; break; /* D */
- case 5: fret_idx = 9; break; /* A */
- default: fret_idx = 4; break; /* E */
- }
-
- for( fret=0; fret < NUM_FRETS; fret++ )
- {
- note = get_note( fret_idx, scale );
- print_note( note, fret );
-
- fret_idx++;
- while( fret_idx > 11 )
- fret_idx -= 12;
- }
- printf( "\n" );
- }
- }
-
- /* ********************************************************************** */
-
- char *get_note( fret_idx, scale )
- unsigned short fret_idx;
- char *scale[];
- /* Returns note if chrom[][fret_idx] is a member of scale[];
- * returns "-" if chrom[][fret_idx] is not a member of scale[].
- */
- {
- register unsigned short i;
-
- for( i=0; i < num_notes; i++ )
- {
- if( streq( scale[i], chrom[FLATS][fret_idx] ) ||
- streq( scale[i], chrom[SHARPS][fret_idx] ) )
- return( scale[i] );
- }
- return( "-" );
- }
-
- /* ********************************************************************** */
-
- void print_note( note, fret )
- char *note;
- unsigned short fret;
- /* Prints note or specified pos_mark_char, then proper fill chars. */
- {
- if( streq( note, "-" ) || (pos_mark_char == '\0') )
- {
- printf( "%s", note );
-
- /* if note is a single-char string, print "-" */
-
- if( (fret > 0) && (*(note + 1) == '\0') )
- printf( "-" );
- }
- else
- {
- printf( "%c", pos_mark_char );
- if( fret > 0 )
- printf( "-" );
- }
-
- switch( fret ) /* print fret indicators */
- {
- case 0: printf( "||-" ); return;
- case 19: printf( "|" ); return;
- default: printf( "|-" ); return;
- }
- }
-
- /* ******************************* END ********************************** */