package items import ( "fmt" "strconv" "strings" ) type EuclideanRhythm struct { StartPos32th uint Notes int Positions int Duration32th int Sketch [][2]string LastPos uint } func (e *EuclideanRhythm) Parse(startPos32th uint, params ...string) error { if len(params) != 3 { return fmt.Errorf("EuclideanRhythm must have 3 params") } e.StartPos32th = startPos32th i, err := strconv.Atoi(params[0]) if err != nil { return fmt.Errorf("number of notes must be an integer") } e.Notes = i i, err = strconv.Atoi(params[1]) if err != nil { return fmt.Errorf("number of positions must be an integer") } e.Positions = i switch len(params[2]) { case 1: switch params[2] { case "&": e.Duration32th = 4 case ",": e.Duration32th = 2 case ";": e.Duration32th = 1 default: qn, err := strconv.Atoi(params[2]) if err != nil { return fmt.Errorf("invalid duration: %#v", params[3]) } e.Duration32th = 8 * qn } case 0: return fmt.Errorf("invalid duration") default: if idx := strings.Index(params[2], "."); idx > 0 { f, err := strconv.ParseFloat(params[2], 64) if err != nil { return fmt.Errorf("invalid duration: %#v", params[2]) } switch f { case 0.5: e.Duration32th = 4 case 0.25: e.Duration32th = 2 case 0.125: e.Duration32th = 1 default: return fmt.Errorf("invalid duration: %#v", params[2]) } } else { qn, err := strconv.Atoi(params[2]) if err != nil { return fmt.Errorf("invalid duration: %#v", params[2]) } e.Duration32th = 8 * qn } } line := euclideanRhythm(e.Notes, e.Positions) e.Sketch = append(e.Sketch, [2]string{"#", ""}) var currentBar uint for i, set := range line { ap := e.StartPos32th + uint(i*e.Duration32th) - (currentBar * 32) if ap >= 32 { currentBar++ e.Sketch = append(e.Sketch, [2]string{"#", ""}) ap -= 32 } pos := Pos32thToString(ap) e.LastPos = ap var val string if set { val = "#1" } else { val = "#2" } e.Sketch = append(e.Sketch, [2]string{pos, val}) } return nil } func euclideanRhythm(onNotes, totalNotes int) []bool { groups := [][]bool{} for i := 0; i < totalNotes; i++ { groups = append(groups, []bool{i < onNotes}) } for l := len(groups) - 1; l > 0; l = len(groups) - 1 { var start = 0 var first = groups[0] for start < l && compareArrays(first, groups[start]) { start++ } if start == l { break } var end = l var last = groups[l] for end > 0 && compareArrays(last, groups[end]) { end-- } if end == 0 { break } var count = min(start, l-end) groups1 := slice(0, count, groups) groups2 := mapp(groups1, func(gr []bool, i int) []bool { return append(gr, groups[l-i]...) }) groups = append(groups2, slice(count, -count, groups)...) } var res []bool for _, gr := range groups { res = append(res, gr...) } return res }