<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/go-audio/music/theory"

	"github.com/go-audio/midi"
)

var (
	ppq          uint32 = 480
	flagFromFreq        = flag.Float64("freq", 0, "Use this frequency as the root of the generated data")
	flagFromNote        = flag.String("root", "", "Root note to use")
	flagOctave          = flag.Int("octave", 3, "Default octave to start from")
	flagIsMinor         = flag.Bool("minor", false, "should we use a minor scale")
)

func main() {
	flag.Parse()
	f, err := os.Create("output.mid")
	if err != nil {
		log.Fatal(err)
	}

	rand.Seed(int64(time.Now().Nanosecond()))

	enc := midi.NewEncoder(f, midi.SingleTrack, uint16(ppq))
	tr := enc.NewTrack()
	tr.AddAfterDelta(0, midi.CopyrightEvent("Generated by Go-Audio"))

	defer func() {
		tr.AddAfterDelta(0, midi.EndOfTrack())
		if err := enc.Write(); err != nil {
			log.Fatal(err)
		}
		f.Close()
	}()

	// generate a chord progression
	// scale
	var scale theory.ScaleName
	if *flagIsMinor {
		scale = theory.MelodicMinorScale
	} else {
		scale = theory.MajorScale
	}

	var rootInt int
	if *flagFromNote != "" {
		rootInt = midi.NotesToInt[strings.ToUpper(*flagFromNote)]
	} else if *flagFromFreq != 0 {
		rootInt = midi.FreqToNote(*flagFromFreq)
	} else {
		// random root
		rootInt = rand.Intn(12)
	}

	// Play the scale notes
	root := midi.Notes[rootInt]
	scaleName := fmt.Sprintf("%s %s scale", root, scale)
	fmt.Println(scaleName)
	keys, notes := theory.ScaleNotes(root, scale)
	fmt.Println("Notes in scale:", notes)
	tr.SetName(fmt.Sprintf("%s %v", scaleName, notes))
	octaveBump := 12 * (*flagOctave + 1)
	// move to the 3rd octave
	for i := 0; i < len(keys); i++ {
		keys[i] += octaveBump
	}

	var progression []int
	if scale == theory.MajorScale {
		n := rand.Intn(len(theory.MajorProgressions))
		progression = theory.MajorProgressions[n]
	} else {
		n := rand.Intn(len(theory.MinorProgressions))
		progression = theory.MinorProgressions[n]
	}

	// playScale(tr, root, scale)
	// fmt.Println()
	playProgression(tr, root, scale, progression)
	fmt.Println()
	playScaleChords(tr, root, scale)
}

func playScaleChords(tr *midi.Track, root string, scale theory.ScaleName) {
	fmt.Println("Chords in scale")
	var timeBuffer uint32
	keys, _ := theory.ScaleNotes(root, scale)<commit_msg>add some euclidian random stuff<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/go-audio/generator/euclidean"

	"github.com/go-audio/music/theory"

	"github.com/go-audio/midi"
)

var (
	ppq          uint32 = 480
	flagFromFreq        = flag.Float64("freq", 0, "Use this frequency as the root of the generated data")
	flagFromNote        = flag.String("root", "", "Root note to use")
	flagOctave          = flag.Int("octave", 3, "Default octave to start from")
	flagIsMinor         = flag.Bool("minor", false, "should we use a minor scale")
)

func main() {
	flag.Parse()
	f, err := os.Create("output.mid")
	if err != nil {
		log.Fatal(err)
	}

	rand.Seed(int64(time.Now().Nanosecond()))

	enc := midi.NewEncoder(f, midi.SingleTrack, uint16(ppq))
	tr := enc.NewTrack()
	tr.AddAfterDelta(0, midi.CopyrightEvent("Generated by Go-Audio"))

	defer func() {
		tr.AddAfterDelta(0, midi.EndOfTrack())
		if err := enc.Write(); err != nil {
			log.Fatal(err)
		}
		f.Close()
	}()

	// generate a chord progression
	// scale
	var scale theory.ScaleName
	if *flagIsMinor {
		scale = theory.MelodicMinorScale
	} else {
		scale = theory.MajorScale
	}

	var rootInt int
	if *flagFromNote != "" {
		rootInt = midi.NotesToInt[strings.ToUpper(*flagFromNote)]
	} else if *flagFromFreq != 0 {
		rootInt = midi.FreqToNote(*flagFromFreq)
	} else {
		// random root
		rootInt = rand.Intn(12)
	}

	root := midi.Notes[rootInt]
	scaleName := fmt.Sprintf("%s %s scale", root, scale)
	fmt.Println(scaleName)
	keys, notes := theory.ScaleNotes(root, scale)
	fmt.Println("Notes in scale:", notes)
	tr.SetName(fmt.Sprintf("%s %v", scaleName, notes))
	octaveBump := 12 * (*flagOctave + 1)
	// move to the target octave
	for i := 0; i < len(keys); i++ {
		keys[i] += octaveBump
	}

	var progression []int
	if scale == theory.MajorScale {
		n := rand.Intn(len(theory.MajorProgressions))
		progression = theory.MajorProgressions[n]
	} else {
		n := rand.Intn(len(theory.MinorProgressions))
		progression = theory.MinorProgressions[n]
	}

	// playScale(tr, root, scale)
	// fmt.Println()
	playProgression(tr, root, scale, progression)
	fmt.Println()
	playScaleChords(tr, root, scale)
	euclideanImprov(tr, root, keys)
}

func euclideanImprov(tr *midi.Track, root string, keys []int) {
	var (
		isAPressed  bool
		isBPressed  bool
		wasAPressed bool
		wasBPressed bool
	)

	var key int
	key = midi.KeyInt(root, 3)
	key2 := keys[rand.Intn(len(keys))]
	// let's play 4 bars
	for i := 0; i < 4; i++ {
		beatsA := euclidean.Rhythm(rand.Intn(16), 16)
		beatsB := euclidean.Rhythm(rand.Intn(16), 16)
		var delta uint32
		for i, on := range beatsA {
			wasAPressed = isAPressed
			wasBPressed = isBPressed
			isAPressed = false
			isBPressed = false
			if on {
				isAPressed = true
				tr.AddAfterDelta(delta, midi.NoteOn(1, key, 99))
				delta = 0
			}
			if beatsB[i] {
				isBPressed = true
				tr.AddAfterDelta(delta, midi.NoteOn(1, key2, 99))
				delta = 0
			}

			if wasAPressed && !isAPressed {
				tr.AddAfterDelta(delta, midi.NoteOff(1, key))
				delta = 0
			}
			if wasBPressed && !isBPressed {
				tr.AddAfterDelta(delta, midi.NoteOff(1, key2))
				delta = 0
			}
			if isAPressed || isBPressed || wasAPressed || wasBPressed {
				delta = ppq / 4
				continue
			}

			delta += ppq / 4
		}
	}
}

func playScaleChords(tr *midi.Track, root string, scale theory.ScaleName) {
	fmt.Println("Chords in scale")
	var timeBuffer uint32
	keys, _ := theory.ScaleNotes(root, scale)
{'fraction_non_alphanumeric': 0.14772338240328656, 'fraction_numerical': 0.013693940431359124, 'mean_word_length': 3.5364906832298137, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2523230', 'n_tokens_mistral': 2437, 'n_tokens_neox': 2184, 'n_words': 511}