Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Fret - FretMutations.cs

FretMutations.cs

Caricato da: Totem
Scarica il programma completo

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Fret;
  6.  
  7. namespace FretMutations
  8. {
  9.     /// <summary>
  10.     /// Rappresenta una mutazione, ossia una variazione casuale, sul tema proposto.
  11.     /// </summary>
  12.     public abstract class FretMutation
  13.     {
  14.         protected Random generator = new Random((Int32)(DateTime.Now.Ticks & 0xFFFFFFFF));
  15.         private Double weight = 1.0;
  16.  
  17.         /// <summary>
  18.         /// Determina il peso di questa mutazione nell'elaborazione finale, ossia quante volte è probabile che questa
  19.         /// variazione venga scelta per modificare il tema originale dal generatore di mutazioni (FretMutationGenerator).
  20.         /// </summary>
  21.         public Double Weight { get { return weight; } set { weight = value; } }
  22.  
  23.         /// <summary>
  24.         /// Applica la mutazione e restituisce il tema modificato.
  25.         /// </summary>
  26.         /// <param name="original">Il tema originale da modificare.</param>
  27.         public abstract FretPiece Apply(FretPiece original);
  28.     }
  29.  
  30.     /// <summary>
  31.     /// Rappresenta una mutazione lambda. Questo tipo di variazione aleatoria può essere applicata più volte ad un singolo
  32.     /// pezzo. La probabilità che venga applicata ad ogni iterazione varia in funzione del parametro lambda, in modo che
  33.     /// all'n-esima iterazione, la probabilità che la mutazione venga applicata almeno ancora una volta è lambda^n.
  34.     /// Perciò per lambda compreso tra 0 e 1 questa probabilità diminuisce esponenzialmente.
  35.     /// </summary>
  36.     public abstract class LambdaFretMutation : FretMutation
  37.     {
  38.         protected Double lambda = 0.5;
  39.         /// <summary>
  40.         /// Indica il parametro lambda della mutazione (compreso tra 0 e 1, estremi esclusi).
  41.         /// </summary>
  42.         public Double Lambda
  43.         {
  44.             get
  45.             { return lambda; }
  46.             set
  47.             {
  48.                 lambda = value;
  49.                 if (lambda < 0)
  50.                     lambda *= -1;
  51.                 if (lambda >= 1.0)
  52.                     lambda -= Math.Truncate(lambda);
  53.             }
  54.         }
  55.     }
  56.  
  57.     /// <summary>
  58.     /// Rappresenta una variazione sulla nota. E' una mutazione lambda che, presa a caso una nota, la sostituisce con un'altra
  59.     /// scelta a caso tra quelle coerenti con la tonalità corrente.
  60.     /// </summary>
  61.     public class NoteVariation : LambdaFretMutation
  62.     {
  63.         public override FretPiece Apply(FretPiece original)
  64.         {
  65.             Double threshold = 1.0;
  66.             FretPiece result = original.TypedClone();
  67.  
  68.             do
  69.             {
  70.                 Int32 randomIndex = this.generator.Next(original.Count);
  71.  
  72.                 if (original[randomIndex].GetType() == Note.Type)
  73.                 {
  74.                     Note note = original[randomIndex] as Note;
  75.                     (result[randomIndex] as Note).Pitch = original.Key.GetDiatonicHarmonic(note.Pitch, generator.Next(2, 8));
  76.                 }
  77.                 threshold *= this.Lambda;
  78.             } while (generator.NextDouble() < threshold);
  79.  
  80.             return result;
  81.         }
  82.     }
  83.  
  84.     /// <summary>
  85.     /// Rappresenta l'aggiunta di accordi. E' una mutazione lambda che, preso a caso una nota, sviluppa su di essa un accordo
  86.     /// con terze, quarte, quinte od ottave (minori, maggiori o giuste a seconda della tonalità).
  87.     /// </summary>
  88.     public class ChordAddition : LambdaFretMutation
  89.     {
  90.         private Byte chordNotes = 1;
  91.         /// <summary>
  92.         /// Indica il numero di note che si vuole porre in accordo (a meno della fondamentale).
  93.         /// </summary>
  94.         public Byte ChordNotes
  95.         {
  96.             get
  97.             { return chordNotes; }
  98.             set
  99.             {
  100.                 chordNotes = value;
  101.                 if (chordNotes < 0)
  102.                     chordNotes = 1;
  103.                 else if (chordNotes > 4)
  104.                     chordNotes = 4;
  105.             }
  106.         }
  107.  
  108.         public override FretPiece Apply(FretPiece original)
  109.         {
  110.             Double threshold = 1.0;
  111.             FretPiece result = original.TypedClone();
  112.  
  113.             do
  114.             {
  115.                 Int32 randomIndex = generator.Next(original.Count);
  116.  
  117.                 if (original[randomIndex].GetType() == Note.Type)
  118.                 {
  119.                     Note note = (original[randomIndex] as Note).Clone() as Note;
  120.                     Chord chord = new Chord();
  121.  
  122.                     chord.Add(note);
  123.                     for(Int32 i = 0; i < chordNotes; i++)
  124.                     {
  125.                         Int32 interval;
  126.                         Note newNote;
  127.                         Double randomValue = generator.NextDouble();
  128.  
  129.                         if (randomValue < 0.3)
  130.                             interval = 3; //terza
  131.                         else if (randomValue >= 0.3 && randomValue < 0.6)
  132.                             interval = 4; // quartza
  133.                         else if (randomValue >= 0.6 && randomValue < 0.9)
  134.                             interval = 5; // quinta
  135.                         else
  136.                             interval = 8;
  137.  
  138.                         //if (generator.NextDouble() > 0.5)
  139.                           //  interval = -interval; // sotto
  140.  
  141.                         newNote = note.Clone() as Note;
  142.                         newNote.Pitch = original.Key.GetDiatonicHarmonic(note.Pitch, interval);
  143.                         if (newNote != null)
  144.                             chord.Add(newNote);
  145.                     }
  146.  
  147.                     result[randomIndex] = chord;
  148.                 }
  149.                 threshold *= lambda;
  150.             } while (generator.NextDouble() < threshold);
  151.  
  152.             return result;
  153.         }
  154.     }
  155.  
  156.     /// <summary>
  157.     /// Rappresenta una trasposizione di ottava. E' una mutazione che traspone tutto il pezzo originale di una
  158.     /// ottava, sopra o sotto, scegliendo a caso.
  159.     /// </summary>
  160.     public class OctaveTransposition : FretMutation
  161.     {
  162.         public override FretPiece Apply(FretPiece original)
  163.         {
  164.             FretPiece result = original.TypedClone();
  165.             SByte octave = (SByte)(generator.NextDouble() > 0.5 ? 1 : -1);
  166.  
  167.             for (Int32 i = 0; i < result.Count; i++)
  168.             {
  169.                 if (result[i].GetType() == Note.Type)
  170.                     (result[i] as Note).Pitch = (result[i] as Note).Pitch.TransposeByOctave(octave);
  171.                 else if (result[i].GetType() == Chord.Type)
  172.                 {
  173.                     foreach (Note note in (result[i] as Chord))
  174.                         note.Pitch = note.Pitch.TransposeByOctave(octave);
  175.                 }
  176.             }
  177.  
  178.             return result;
  179.         }
  180.     }
  181.  
  182.     /// <summary>
  183.     /// Rappresenta una divisione di note. E' una mutazione lambda che sostituisce ad una singola nota altre due note
  184.     /// di durata dimezzata, di cui la prima ha la stessa altezza e inflessione dell'originale e la seconda è scelta a caso.
  185.     /// </summary>
  186.     public class NoteSplitting : LambdaFretMutation
  187.     {
  188.         public override FretPiece Apply(FretPiece original)
  189.         {
  190.             Double threshold = 1.0;
  191.             FretPiece result = original.TypedClone();
  192.  
  193.             do
  194.             {
  195.                 Int32 randomIndex = generator.Next(result.Count);
  196.  
  197.                 if (result[randomIndex].GetType() == Note.Type)
  198.                 {
  199.                     Note note = result[randomIndex] as Note;
  200.                     Note nextNote;
  201.                     note.Duration = new Fraction(note.Duration.Numerator, note.Duration.Denumerator * 2);
  202.                     nextNote = note.CloneAndTrasposeByInterval(original.Key, 1 + generator.Next(1, 5));
  203.                     result.Insert(randomIndex, nextNote);
  204.                 }
  205.                 threshold *= lambda;
  206.             } while (generator.NextDouble() < threshold);
  207.  
  208.             return result;
  209.         }
  210.     }
  211.  
  212.     /// <summary>
  213.     /// Rappresenta una simmetria verticale. E' una mutazione che traspone tutto il pezzo originale in modo da ottenerne
  214.     /// una versione speculare rispetto alla tonica della tonalità.
  215.     /// </summary>
  216.     public class HarmonicSymmetry : FretMutation
  217.     {
  218.         public override FretPiece Apply(FretPiece original)
  219.         {
  220.             FretPiece result = new FretPiece();
  221.  
  222.             result.Meter = original.Meter.Clone() as Meter;
  223.             result.Key = original.Key.Clone() as Key;
  224.             result.Tempo = original.Tempo.Clone() as Tempo;
  225.             foreach (IGuidoElement element in original)
  226.             {
  227.                 try
  228.                 {
  229.                     if (element.GetType() == Note.Type)
  230.                     {
  231.                         Note note = element as Note;
  232.                         Int32 offset = note.Pitch.GetDistance(original.Key.KeyNotes[0]);
  233.                         result.Add(note.CloneAndTranspose(2 * offset, note.Pitch.Accidentals));
  234.                     }
  235.                     else if (element.GetType() == Chord.Type)
  236.                     {
  237.                         Chord chord = new Chord();
  238.                         foreach (Note note in (element as Chord))
  239.                         {
  240.                             Int32 offset = note.Pitch.GetDistance(original.Key.KeyNotes[0]);
  241.                             chord.Add(note.CloneAndTranspose(2 * offset, note.Pitch.Accidentals));
  242.                         }
  243.                         result.Add(chord);
  244.                     }
  245.                     else if (element.GetType() == Pause.Type)
  246.                         result.Add((element as Pause).Clone() as Pause);
  247.                 }
  248.                 catch
  249.                 {
  250.                     throw new ArgumentOutOfRangeException("Impossibile applicare la mutazione 'HarmonicSymmetry', poiché alcune note distano troppo dalla tonica dell'ottava centrale.");
  251.                 }
  252.             }
  253.  
  254.             return result;
  255.         }
  256.     }
  257.  
  258.     /// <summary>
  259.     /// Rappresenta una traslazione verticale. E' una mutazione che traspone tutto il pezzo originale in su o in giù di intervalli
  260.     /// di terza, quarta, quinta o sesta (maggiori o minori), scelti a caso.
  261.     /// </summary>
  262.     public class VerticalTranslation : FretMutation
  263.     {
  264.         private static Int32[] possibleShifts = new Int32[] { 3, 4, 5, -4, -5, -6 };
  265.  
  266.         public override FretPiece Apply(FretPiece original)
  267.         {
  268.             Int32 randomShift = possibleShifts[generator.Next(0, possibleShifts.Length)];
  269.             FretPiece result = new FretPiece();
  270.  
  271.             randomShift = 4;
  272.             result.Meter = original.Meter.Clone() as Meter;
  273.             result.Key = original.Key.Clone() as Key;
  274.             result.Tempo = original.Tempo.Clone() as Tempo;
  275.             foreach (IGuidoElement element in original)
  276.             {
  277.                 if (element.GetType() == Note.Type)
  278.                     result.Add((element as Note).CloneAndTrasposeByInterval(original.Key, randomShift));
  279.                 else if (element.GetType() == Chord.Type)
  280.                 {
  281.                     Chord chord = new Chord();
  282.                     foreach (Note note in (element as Chord))
  283.                         chord.Add(note.CloneAndTrasposeByInterval(original.Key, randomShift));
  284.                     result.Add(chord);
  285.                 }
  286.                 else if (element.GetType() == Pause.Type)
  287.                     result.Add((element as Pause).Clone() as Pause);
  288.             }
  289.  
  290.             return result;
  291.         }
  292.     }
  293.  
  294.     /// <summary>
  295.     /// Traspone tutto il pezzo dalla maggiore alla relativa minore, o viceversa.
  296.     /// </summary>
  297.     public class RelativeTransposition : FretMutation
  298.     {
  299.         public override FretPiece Apply(FretPiece original)
  300.         {
  301.             FretPiece result = new FretPiece();
  302.             Int32 offset = 0;
  303.  
  304.             result.Meter = original.Meter.Clone() as Meter;
  305.             result.Key = original.Key.Clone() as Key;
  306.             result.Key.IsMajor = !original.Key.IsMajor;
  307.             result.Tempo = original.Tempo.Clone() as Tempo;
  308.             if (original.Key.IsMajor) // va in minore, -3
  309.                 offset = -3;
  310.             else
  311.                 offset = +3;
  312.  
  313.             foreach (IGuidoElement element in original)
  314.             {
  315.                 if (element.GetType() == Note.Type)
  316.                     result.Add((element as Note).CloneAndTrasposeByInterval(original.Key, offset));
  317.                 else if (element.GetType() == Chord.Type)
  318.                 {
  319.                     Chord chord = new Chord();
  320.                     foreach (Note note in (element as Chord))
  321.                         chord.Add(note.CloneAndTrasposeByInterval(original.Key, offset));
  322.                     result.Add(chord);
  323.                 }
  324.                 else if (element.GetType() == Pause.Type)
  325.                     result.Add((element as Pause).Clone() as Pause);
  326.             }
  327.  
  328.             return result;
  329.         }
  330.     }
  331.  
  332.     /// <summary>
  333.     /// Rappresenta il passaggio a ritmo sincopato. E' una mutazione lambda simile a NoteSplitting, ma in cui la prima delle due note costituisce 3/4 della durata totale.
  334.     /// </summary>
  335.     public class RagtimeTransformation : LambdaFretMutation
  336.     {
  337.         public override FretPiece Apply(FretPiece original)
  338.         {
  339.             Double threshold = 1.0;
  340.             FretPiece result = original.TypedClone();
  341.  
  342.             do
  343.             {
  344.                 Int32 randomIndex = generator.Next(result.Count);
  345.  
  346.                 if (result[randomIndex].GetType() == Note.Type)
  347.                 {
  348.                     Note note = result[randomIndex] as Note;
  349.                     Note nextNote;
  350.                     note.Duration = new Fraction(note.Duration.Numerator, note.Duration.Denumerator * 2);
  351.                     nextNote = note.CloneAndTrasposeByInterval(original.Key, 1 + generator.Next(1, 5));
  352.                     note.NumberOfDots++;
  353.                     nextNote.Duration = new Fraction(nextNote.Duration.Numerator, nextNote.Duration.Denumerator * 2);
  354.                     result.Insert(randomIndex, nextNote);
  355.                 }
  356.                 threshold *= lambda;
  357.             } while (generator.NextDouble() < threshold);
  358.  
  359.             return result;
  360.         }
  361.     }
  362.  
  363.     /// <summary>
  364.     /// Rappresenta un generatore di mutazioni, che gestisce le variazioni su un singolo tema.
  365.     /// </summary>
  366.     public class FretMutationGenerator
  367.     {
  368.         protected Random generator = new Random((Int32)(DateTime.Now.Ticks & 0xFFFFFFFF));
  369.         /// <summary>
  370.         /// Una lista che contiene tutte le mutazioni che questo generatore può applicare, con i rispettivi pesi e parametri.
  371.         /// </summary>
  372.         public List<FretMutation> Mutations { get; set; }
  373.  
  374.         public FretMutationGenerator()
  375.         {
  376.             this.Mutations = new List<FretMutation>();
  377.         }
  378.  
  379.         /// <summary>
  380.         /// Applica le mutazioni contenute in Mutations con una certa casualità. La probabilità di ciascuna mutazione di
  381.         /// essere applicata è proporzionale al suo peso. Produce una sequenza di FretPiece, ciascuno mutato diversamente.
  382.         /// </summary>
  383.         /// <param name="original">Il tema originale da modificare.</param>
  384.         /// <param name="iterations">Il numero di iterazioni del processo. Ogni iterazione produce un tema modificato,
  385.         /// prendendo come originale uno dei temi già prodotti e applicando una mutazione a caso.</param>
  386.         public Fret.Fret ApplyMutations(FretPiece original, Int32 iterations)
  387.         {
  388.             Double[] mutationsProbabilities;
  389.             Double totalWeight = this.Mutations.Sum(item => item.Weight);
  390.             Double tmp;
  391.             Fret.Fret result = new Fret.Fret();
  392.             mutationsProbabilities = this.Mutations.Select(item => (item.Weight / totalWeight)).ToArray();
  393.             result.Add(original);
  394.             for (Int32 i = 0; i < iterations; i++)
  395.             {
  396.                 Double rnd = generator.NextDouble();
  397.                 tmp = 0;
  398.                 for(Int32 j = 0; j < mutationsProbabilities.Length; j++)
  399.                 {
  400.                     if (tmp <= rnd && rnd < tmp + mutationsProbabilities[j])
  401.                     {
  402.                         result.Add(this.Mutations[j].Apply(result[generator.Next(0, result.Count)]));
  403.                         break;
  404.                     }
  405.                     tmp += mutationsProbabilities[j];
  406.                 }
  407.             }
  408.  
  409.             return result;
  410.         }
  411.  
  412.         /// <summary>
  413.         /// Applica le mutazioni contenute in Mutations con una certa casualità. La probabilità di ciascuna mutazione di
  414.         /// essere applicata è proporzionale al suo peso. A differenza di ApplyMutations, in questo caso tutte le mutazioni vengono
  415.         /// riapplicate a un singolo pezzo.
  416.         /// </summary>
  417.         /// <param name="original">Il tema originale da modificare.</param>
  418.         /// <param name="iterations">Il numero di iterazioni del processo. Ogni iterazione produce un tema modificato,
  419.         /// prendendo come originale il tema mutato precedentemente.</param>
  420.         public Fret.Fret ApplyIncrementalMutations(FretPiece original, Int32 iterations)
  421.         {
  422.             Double[] mutationsProbabilities;
  423.             Double totalWeight = this.Mutations.Sum(item => item.Weight);
  424.             Double tmp;
  425.             Fret.Fret result = new Fret.Fret();
  426.             FretPiece mutatedTheme = original.TypedClone();
  427.             mutationsProbabilities = this.Mutations.Select(item => (item.Weight / totalWeight)).ToArray();
  428.            
  429.             for (Int32 i = 0; i < iterations; i++)
  430.             {
  431.                 Double rnd = generator.NextDouble();
  432.                 tmp = 0;
  433.                 for (Int32 j = 0; j < mutationsProbabilities.Length; j++)
  434.                 {
  435.                     if (tmp <= rnd && rnd < tmp + mutationsProbabilities[j])
  436.                     {
  437.                         mutatedTheme = this.Mutations[j].Apply(mutatedTheme);
  438.                         break;
  439.                     }
  440.                     tmp += mutationsProbabilities[j];
  441.                 }
  442.             }
  443.  
  444.             result.Add(mutatedTheme);
  445.             return result;
  446.         }
  447.     }
  448. }