func UploadProc() { log.Println("starting upload proc") // read md5 to ID mapping // read ID to analysis mapping hasher := md5.New() e := echonest.New() if echonestkey != "" { e.Key = echonestkey } for r := range UploadChan { log.Println("got", len(r.Data), "bytes", r.Filetype, "add", r.Add, "playback", r.Playback) // md5 data and see if we have analysis already var m md5sum hasher.Write(r.Data) copy(m[:], hasher.Sum(nil)) hasher.Reset() var id string var ok bool var a Analysis var url string var err error if id, ok = GetIDForChecksum(m); !ok { // log.Println("no id for md5", m) // if not upload it to analyzer. id, url, err = e.Upload(r.Filetype, r.Data) if err != nil { log.Println("error uploading track to EN", err) continue } // log.Println("got ID", id, "url", url, "err", err) // update md5 to id mapping AddIDForChecksum(m, id) } // if it comes back with an ID that we have, then great! // if not then fetch the detailed analysis // update id to analysis mapping if a, ok = GetSegmentsForID(id); !ok { a, err = DetailsForID(url, id) if err != nil { log.Println("error getting details from EN", err) continue } SetSegmentsForID(id, a) } go func() { // if it's marked "add" open data with sox sub process (for mp3, mp4, and m4a support) to get raw samples has := (a.Segments[0].File != "") if r.Add && !has { buf, err := openBuf(r.Data, r.Filetype) if err != nil { log.Println("couldn't get sox to run", err) return } // put raw samples into files for i := range a.Segments { filename := id + "_" + strconv.Itoa(a.Segments[i].Index) filename = path.Join(samplepath, filename) file, err := os.Create(filename) if err != nil { log.Println("couldn't open file", filename, err) continue } bytecount := int(a.Segments[i].Duration*float64(samplerate)) * 4 // 2 bytes per sample * 2 channels per frame // log.Println(a.segments[i].Duration, bytecount) _, err = file.Write(buf[:bytecount]) if err != nil { log.Println("error writing sample", err) } file.Close() a.Segments[i].File = filename } // add to all segments // log.Println("adding to all segs") go func() { attributionChan <- en_tuple{id, playq{a.Artist, a.Title, r.Fma_url}} }() AddToAllSegs(a.Segments) // log.Println("done adding to all segs") } // if request is marked "playback" add the ID to the request queue if r.Playback { RequestQueue <- id } }() } }
func RequestProc() { log.Println("starting RequestProc") e := echonest.New() if echonestkey != "" { e.Key = echonestkey } for r := range RequestQueue { log.Println("got request for ID", r) // see if we have analysis for this ID s, ok := GetSegmentsForID(r) if !ok { url, err := e.Analyze(r) // if we don't have analysis see if echonest does if err != nil { log.Println("error grabbing analysis from EN", err) continue } s, err = DetailsForID(url, r) if err != nil { log.Println("error grabbing analysis from EN", err) continue } } playqlock.Lock() // log.Println("putting",s.Artist,s.Title,"to queue") playqueue[playq{s.Artist, s.Title, ""}] = true playqlock.Unlock() // once we get analysis, start grabbing samples go func() { var ar AudioRequest allSegsLock.RLock() defer allSegsLock.RUnlock() expectedlen := float64(0) outlen := float64(0) var totdist float64 for _, segment := range s.Segments { // var ss SegSortSlice // m := make(map[SegmentID]bool) /* var pitches = []int{12,12,12} // find highest three pitches in segment for note, p := range segment.Pitches[:] { if pitches[0] == 12 || p > segment.Pitches[pitches[0]] { pitches[2], pitches[1], pitches[0] = pitches[1], pitches[0], note } else if pitches[1] == 12 || p > segment.Pitches[pitches[1]] { pitches[2], pitches[1] = pitches[1], note } else if pitches[2] == 12 || p > segment.Pitches[pitches[2]] { pitches[2] = note } } for index, n := range pitches { i := 0 for k := range m { m[k] = false } for _, v := range allSegs.Pitch[n].Segments[int(segment.Pitches[n] / allSegs.Pitch[n].Width)] { if _, ok := m[v]; (index == 0) || ok { i++ m[v] = true } } if i <= 100 { break } }*/ // ss.slice = make([]Segment, 0, len(m)) closestDistance := float64(-1) var nearestSeg SegmentID for k, b := range allSegs.Segs { if allSegs.Segs[k].LoudnessMax > Loudness_min { thisDist := Distance(&segment, &b) if closestDistance < 0 || thisDist < closestDistance { fi, err := os.Stat(b.File) if err != nil || fi.IsDir() { log.Println("couldn't stat", b.File, "nil means IsDir", err) continue } closestDistance = thisDist nearestSeg = k } } } // ss.root = segment // sort.Sort(ss) // if len(ss.slice) > 0 { // for snum := 0; snum < len(ss.slice); snum++ { var outs Segment = allSegs.Segs[nearestSeg] totdist += outs.Distance // var mindist float64 = -1 // var distcount int // for _, b := range allSegs.Segs { // outs = b // if mindist < 0 { // mindist = Distance(&segment, &outs) // log.Println("m", mindist) // } else if distcount < 10 { // if d := Distance(&segment, &outs); d < mindist { // mindist = d // distcount++ // log.Println(mindist) // } // } else { // break // } // } outs.RootDuration = segment.Duration outs.RootLoudnessMax = segment.LoudnessMax outs.RootLoudnessStart = segment.LoudnessStart outlen += segment.Duration ar.segments = append(ar.segments, outs) // } // } expectedlen += segment.Duration } log.Println("avg distance", totdist/float64(len(ar.segments))) // log.Println(expectedlen, outlen) ar.artist = s.Artist ar.title = s.Title AudioQueue <- ar }() } }