auto-musik

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

generator.rs (3263B)


      1 use crate::data::{Bar, Beat, Chord, NoteEvent, Tonality};
      2 use rand::Rng;
      3 use std::collections::HashMap;
      4 
      5 pub struct MusicGenerator {
      6     previous_state: Chord,
      7     transition_model: HashMap<Chord, Vec<(Chord, u32)>>,
      8 }
      9 
     10 impl MusicGenerator {
     11     pub fn new() -> Self {
     12         use Chord::*;
     13         let mut model = HashMap::new();
     14 
     15         model.insert(
     16             First,
     17             vec![
     18                 (Fourth, 5), // I -> IV (F) に行きやすい
     19                 (Fifth, 3),  // I -> V (G) もあり
     20                 (Sixth, 2),  // I -> VI (Am) もあり
     21                 (First, 1),  // I のまま留まる
     22             ],
     23         );
     24 
     25         model.insert(
     26             Fourth,
     27             vec![
     28                 (Fifth, 8), // IV -> V (G) に行きやすい
     29                 (First, 2), // IV -> I (C) に戻る
     30             ],
     31         );
     32 
     33         model.insert(
     34             Fifth,
     35             vec![
     36                 (First, 10), // V -> I (C) に戻るのが基本
     37             ],
     38         );
     39 
     40         model.insert(Sixth, vec![(Fourth, 5), (First, 5)]); // Am -> F or C
     41         model.insert(Second, vec![(Fifth, 10)]); // Dm -> G
     42 
     43         MusicGenerator {
     44             previous_state: First, // 初期状態は I (C)
     45             transition_model: model,
     46         }
     47     }
     48 
     49     pub fn generate_next_bar(&mut self) -> Bar {
     50         let next_chord = self.choose_next_state();
     51 
     52         let next_bar = self.generate_events_for_chord(next_chord);
     53 
     54         self.previous_state = next_chord;
     55         next_bar
     56     }
     57 
     58     fn choose_next_state(&self) -> Chord {
     59         let options = self
     60             .transition_model
     61             .get(&self.previous_state)
     62             .unwrap_or_else(|| panic!("there no code {:?} on this model", self.previous_state));
     63 
     64         let total_weight: u32 = options.iter().map(|(_, w)| w).sum();
     65         let mut rng = rand::rng();
     66         let mut target = rng.random_range(0..total_weight);
     67 
     68         for (state, weight) in options {
     69             if target < *weight {
     70                 return *state;
     71             }
     72             target -= weight;
     73         }
     74         options[0].0
     75     }
     76 
     77     fn generate_events_for_chord(&self, chord: Chord) -> Bar {
     78         let root_note = match chord {
     79             Chord::First => 60,   // C4
     80             Chord::Second => 62,  // D4
     81             Chord::Third => 64,   // E4
     82             Chord::Fourth => 65,  // F4
     83             Chord::Fifth => 67,   // G4
     84             Chord::Sixth => 69,   // A4
     85             Chord::Seventh => 71, // B4
     86         };
     87 
     88         let mut events = Vec::new();
     89         const NOTE_DURATION: u64 = 480; // 500ms - 20ms の隙間
     90 
     91         for i in 0..4 {
     92             let time_ms = (i as u64) * 500;
     93 
     94             events.push((
     95                 time_ms,
     96                 NoteEvent::NoteOn {
     97                     note: root_note,
     98                     velocity: 90,
     99                 },
    100             ));
    101             events.push((
    102                 time_ms + NOTE_DURATION,
    103                 NoteEvent::NoteOff { note: root_note },
    104             ));
    105         }
    106 
    107         Bar {
    108             beat: Beat::FourFourth,
    109             tonality: Tonality::CM,
    110             chord,
    111             events,
    112         }
    113     }
    114 }