func loadSong(filename string) (song Song, err error) { f, err := os.Open(filename) if err != nil { return } song.Info = make(map[string]string) id3info := id3.Read(f) if id3info != nil { song.Info["title"] = id3info.Name song.Info["artist"] = id3info.Artist } song.Info["filename"] = filename f.Close() arguments := []string{filename} arguments = append(arguments, soxFormat...) arguments = append(arguments, "-") arguments = append(arguments, soxTrim(30, 4)...) cmd := exec.Command("sox", arguments...) buffer := new(bytes.Buffer) cmd.Stdout = buffer err = cmd.Run() if err != nil { return Song{}, err } samples := make([]float64, buffer.Len()) for i, sample := range buffer.Bytes() { samples[i] = float64(sample) } spectrogram := spectral.Compute(samples, 1024, 0.75) statistics := spectrogram.Stats(22050) features := []string{"cutoffFreq", "energyCV", "maxEnergyFreq", "maxVarFreq"} song.Features = make([]float64, 0, len(features)) for _, stat := range features { song.Features = append(song.Features, statistics[stat]) } song.Features = append(song.Features, spectrogram.LogFreq...) return }
// MusicPick lets the user pick playlist tracks from local files func MusicPick(inDirectory, outDirectory string, tracks Tracks) (err error) { var id3Files []*id3.File var filePaths []string // Traverse all folders inside inDirectory and load all music files walkFunc := func(path string, info os.FileInfo, err error) error { if err != nil { return err } stat, err := os.Stat(path) if err != nil { return err } // We only open files if stat.IsDir() { return nil } // Only open .mp3 and .flac files if !strings.HasSuffix(strings.ToLower(path), ".mp3") && !strings.HasSuffix(strings.ToLower(path), ".flac") { return nil } // Open file fd, err := os.Open(path) if err != nil { return err } defer fd.Close() // Read id3 id3File := id3.Read(fd) if id3File == nil { errorf("could not read id3 tags\n") return nil } // Add to slice id3Files = append(id3Files, id3File) filePaths = append(filePaths, path) return err } if err = filepath.Walk(inDirectory, walkFunc); err != nil { return } // Go through each track and try to find it. for i, x := range tracks { fmt.Fprintf(color.Output, "[%d / %d] Locating track: %s Artist: %s\n", i, len(tracks)-1, boldS(x.Name), boldS(x.ArtistName)) var matchedID3s []*id3.File var matchedFilepaths []string for k, y := range id3Files { // Match algorithm a, b := strings.ToLower(y.Artist), strings.ToLower(x.ArtistName) if strings.Contains(a, b) || strings.Contains(b, a) { matchedID3s = append(matchedID3s, y) matchedFilepaths = append(matchedFilepaths, filePaths[k]) } } // Continue to next track if we got no results if len(matchedID3s) < 1 { logf("No matches\n") continue } } return }
func getSongs() []SongRecord { addfilechannel := make(chan SongRecord, 100) var w sync.WaitGroup for _, playlistRec := range IcerayCfg.Playlist { fext := strings.ToLower(filepath.Ext(playlistRec.Path)) if fext == ".xspf" { // process XML playlist file } else if fext == ".m3u" { // process m3u playlist file } else { w.Add(1) go folderSearch(playlistRec.Path, playlistRec.Subdirs, addfilechannel, &w) } } // wait for song search(es) to finish up w.Wait() close(addfilechannel) var songs []SongRecord for mfile := range addfilechannel { // Read in MP3 info and save it fd, err := os.Open(mfile.fullpath) defer fd.Close() if err != nil { log.Println("Problem opening: " + mfile.fullpath) continue } // Read in MP3 tags mp3tags := id3.Read(fd) if mp3tags == nil { log.Println("Problems getting MP3 tags for " + mfile.fullpath) continue } if mp3tags.Artist == "" { log.Println("Artist tag missing for " + mfile.fullpath) continue } if mp3tags.Name == "" { log.Println("Song tag missing for " + mfile.fullpath) continue } mfile.artist = mp3tags.Artist mfile.title = mp3tags.Name songs = append(songs, mfile) } if IcerayCfg.Music.Shuffle { // Now (linear) shuffle it sc := len(songs) for i := range songs { j := randGen.Intn(sc) songs[i], songs[j] = songs[j], songs[i] } } return songs }