#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "note.h"
/* ===> DESCRIZIONE <===========================================================
ASSETTO ARMONICO, di Aldo Carpanelli, maggio 2016
Data una tonica, il programma elabora la scala maggiore corrispondente e le
triadi che costituiscono l'assetto armonico di base della tonalita'.
Gli accordi sono divisi in tre livelli:
1. i "cardini" della tonalita'
(I, IV e V grado, accordi maggiori)
2. il \"lato oscuro\" della tonalita'
(II, III e VI grado, accordi minori)
3. la sensibile della scala
(l'unica triade diminuita che deriva
direttamente da una scala maggiore)
Il formato di immissione della tonica deve essere simile a questo: fa#
==============================================================================*/
// ===> STRINGHE <==============================================================
// la LUNGA stringa per la presentazione del programma!
const char *kStrPresentazioneProgramma =
" ==============================================================================\n\
SCALE E ACCORDI\n\
==============================================================================\n\
\n\
Data una tonica, il programma elabora la scala maggiore corrispondente e le\n\
triadi che costituiscono l'assetto armonico di base della tonalita'.\n\
\n\
Gli accordi sono divisi in tre livelli:\n\
\n\
1. i \"cardini\" della tonalita'\n\
(I, IV e V grado, accordi maggiori)\n\
2. il \"lato oscuro\" della tonalita'\n\
(II, III e VI grado, accordi minori)\n\
3. la sensibile della scala\n\
(l'unica triade diminuita che deriva\n\
direttamente da una scala maggiore)\n\
\n\
Il formato di immissione della tonica deve essere simile a questo: fa#\n";
const char *kStrNomiNote[7] = { "DO","RE","MI","FA","SOL","LA","SI" };
// ===> PROTOTIPI DI FUNZIONI <=================================================
void ChiediTonica( int *tonica, int *alterazione );
void VisualizzaProspetto( SCALA *s,
NOTA *I, NOTA *II, NOTA *III, NOTA *IV, NOTA *V, NOTA *VI, NOTA *VII );
// ===> DEFINIZIONI DI FUNZIONI <===============================================
int main() {
char schema[7] = { 2, 2, 1, 2, 2, 2, 1 }; // lo schema della scala maggiore
NOTA I[3], II[3], III[3], IV[3], V[3], VI[3], VII[3]; // per le triadi
int tonica, alterazione; // per l'immissione della tonica della scala
SCALA s; // ovvio
OttavaVisibile( false ); // le stringhe col nome delle note NON
// comprenderanno il numero dell'ottava
while( true ) { // ciclo infinito
system( "cls" ); // svuota la console
// spiega in poche parole cosa fa il programma
printf( kStrPresentazioneProgramma );
// chiede all'utente di immettere la tonica alla base della scala
ChiediTonica( &tonica, &alterazione );
// l'oggetto scala calcola le proprie impostazioni in base alla
// tonica immessa, usando sempre lo schema della scala maggiore
s.Imposta( tonica, alterazione, schema );
s.Triade( 0, I ); // l'oggetto SCALA s "compila" gli
s.Triade( 1, II ); // array di tre oggetti NOTA con
s.Triade( 2, III ); // le note che costituiscono gli
s.Triade( 3, IV ); // accordi costruiti sui gradi
s.Triade( 4, V );
s.Triade( 5, VI );
s.Triade( 6, VII );
// compila la tabella coi risultati dell'elaborazione
VisualizzaProspetto( &s, I, II, III, IV, V, VI, VII );
system( "pause" ); // attende, per dar tempo all'utente
// di consultare la tabella (non e'
// mica un computer, lui!!!)
} // "rimbalza" all'inizio del ciclo per un'eventuale nuova richiesta
return 0; // qui non si arriva mai, ma e' richiesto
}
/*==============================================================================
DESCRIZIONE
Chiede e richiede l'immissione di una nota da utilizzare come tonica della scala
da creare. La richiesta viene iterata fino all'ottenimento di un'immissione
valida.
PARAMETRI
tonica Un puntatore a un valore intero che punta all'area di memoria
nella quale verra' inserito il numero d'ordine della tonica
immessa (zero based). Se il puntatore e' NULL, la funzione
fallisce.
alterazione Un puntatore a un valore intero che punta all'area di memoria
nella quale verra' inserito il grado di alterazione della tonica
immesso (zero based). Se il puntatore e' NULL, la funzione
fallisce.
FORMATO DI IMMISSIONE DELLA TONICA
La tonica deve essere immessa sotto forma del nome della nota seguito dalla
eventuale alterazione. Ad esempio, "re", "fa#", "sol", "lab" (senza virgolette).
==============================================================================*/
void ChiediTonica( int *tonica, int *alterazione ) {
if( tonica == NULL || alterazione == NULL ) return;
int tTemp = 0x7FFF, aTemp = 0x7FFF; // valori non validi
const int kDimBuff = 16;
char buff[kDimBuff];
char *p;
int i, l;
// chiede la prima volta
printf( "\n Inserisci la tonica della scala: " );
// ripete fino a che non ottiene un immissione valida
while( tTemp == 0x7FFF || aTemp == 0x7FFF ) {
tTemp = 0x7FFF; // preimposta un valore non valido
aTemp = 0x7FFF; // preimposta un valore non valido
p = buff; // "p" e' un alias
// rileva l'input in buff, tramite il puntatore p
fgets( p, kDimBuff, stdin );
for( l=0; p[l]; ++l );
if( p[l-1]=='\n' ) p[--l] = '\0';
for( i=0; i<l; ++i ) p[i] = toupper(p[i]); // tutto maiuscolo!
// scopre il numero che corrisponde al nome della nota
for( i=0; i<7; ++i )
if( strncmp(kStrNomiNote[i],p,2) == 0 )
break;
if( i != 7 ) { // se i==7, non ha trovato un nome di nota valido
tTemp = i;
// cerca le alterazioni
while( *p!='B' && *p!='#' && *p!='\0' ) ++p;
if( *p == '\0' ) {
aTemp = 0; // in questo caso, non ci sono alterazioni
}
else {
if( *p == '#' ) // c'e' un diesis
for( aTemp=0; *p++ == '#'; ++aTemp );
else if( *p == 'B' ) // c'e' un bemolle
for( aTemp=0; *p++ == 'B'; --aTemp );
}
// il programma non ammette che la
// tonica abbia diesis o bemolle doppi
if( aTemp < -1 || aTemp > 1 ) {
// rinnova la rischiesta
aTemp = 0x7FFF; // attribuisce ad aTemp un valore non valido
printf( "\n Tonica non valida, riprova: " );
}
}
else {
// rinnova la rischiesta
printf( "\n Tonica non valida, riprova: " );
}
} // ripete il "while" fino a che non ottiene un'immissione valida
// accetta tonica e alterazione trovate e le immette negli spazi di memoria
// puntati dai puntatori che costituiscono i parametri della funzione
*tonica = tTemp;
*alterazione = aTemp;
}
/*==============================================================================
DESCRIZIONE
Stampa sullo schermo la tabella per la visualizzazione della scala e degli
accordi elaborati.
PARAMETRI
s Un puntatore a un oggetto di classe SCALA che rappresenta la scala
di riferimento della tonalita' richiesta in immissione.
I, II ecc. Puntatori di riferimento ad array di tre oggetti di classe NOTA che
rappresentano le triadi sui diversi gradi della scala.
==============================================================================*/
void VisualizzaProspetto( SCALA *s,
NOTA *I, NOTA *II, NOTA *III, NOTA *IV, NOTA *V, NOTA *VI, NOTA *VII ) {
int i, j, tonica, alterazione;
// rileva il numero della nota corrispondente alla tonica
tonica = s->Grado(0).Nota();
// ricava l'eventuale alterazione della tonica
alterazione = s->Grado(0).Alterazione();
system( "cls" ); // svuota la console
// intesta la tabella
printf( "\n ASSETTO ARMONICO DELLA SCALA DI " );
printf( "%s", kStrNomiNote[tonica] );
if( alterazione == -1 )
printf( " BEMOLLE" );
else if( alterazione == 1 )
printf( " DIESIS" );
printf( " MAGGIORE\n " );
// stampa una riga
for( i=0; i<54; ++i ) printf( "=" );
// stampa l'intestazione delle colonne dei gradi della scala
printf( "\n |%-6s|%-6s|%-6s|%-6s|%-6s|%-6s|%-6s|%-6s",
"I", "II", "III", "IV", "V", "VI", "VII", "VIII" );
// stampa i nomi dei gradi della scala
printf( "\n " );
for( i=0; i<8; ++i ) printf( "%-7s", "|" );
printf( "\n " );
for( i=0; i<8; ++i ) printf( "|%-6s", s->Grado(i).Str() );
printf( "\n " );
for( i=0; i<7; ++i ) printf( "%-7s", "|" );
// stampa gli accordi di I, IV e V grado
for( i=0; i<3; ++i ) {
printf( "\n |%-6s", I[2-i].Str() );
printf( "%-7s%-7s", "|", "|" );
printf( "|%-6s", IV[2-i].Str() );
printf( "|%-6s", V[2-i].Str() );
printf( "%-7s%-7s", "|", "|" );
}
// stampa gli accordi di II, III e VI grado
for( i=0; i<3; ++i ) {
printf( "\n |%-6s", II[2-i].Str() );
printf( "|%-20s", III[2-i].Str() );
printf( "|%-6s", VI[2-i].Str() );
printf( "%-7s", "|" );
}
// stampa l'accordo di VII grado (sensibile)
for( i=0; i<3; ++i ) {
printf( "\n" );
for( j=0; j<43; ++j ) printf( " " );
printf( "|%-6s", VII[2-i].Str() );
}
printf( "\n\n " ); // doppio "a capo"
}