Beispiel #1
0
int main(int argc, char* argv[])
{
  RunTests();

  // Our tracks
  Tracks tracks;
  vector<string> names;
  //GetTracks("tracks.txt", tracks);
  GetTracksTabSeparated("tracks_tsv.txt", tracks, names);

  //// Write separate values out
  //ofstream names("names.txt");
  //ofstream bpms("bpms.txt");
  //ofstream keys("keys.txt");
  //for (auto t : tracks) {
  //  names << t.name           << endl;
  //  bpms  << t.bpm            << endl;
  //  keys  << t.key.short_name << endl;
  //}
  //names.close();
  //bpms.close();
  //keys.close();

  // Collect stats on how many tracks are in which keys
  KeyCount key_counts;
  for (auto t : tracks) {
    //key_counts[t.key].push_back(t);
    key_counts[t.key]++;
  }

  // Write the key counts
  for (auto k : key_counts) {
    cout << Key::GetShortName(k.first.num, k.first.type) << ": " << k.second << endl;
  }

  // Exhaustive solution
  // Start at each track and try to get as many tracks into a mix as possible
  // We will exhaustively try to join into each possible next track that is compatible
  Tracks available = tracks;
  Tracks best;
  double best_cost = DBL_MAX;
  for (size_t i = 0; i < available.size(); ++i) {
    Tracks chosen;
    Tracks this_best;
    double cost = 0;
    double this_best_cost = DBL_MAX;

    int its = 0;
    Tracks now_available = available;
    Track t = now_available[i];
    now_available.erase(now_available.begin() + i);
    Tracks now_chosen = chosen;
    now_chosen.push_back(t);
    cout << "Starting with " << names[t.idx] << endl;
    ChooseTrack(names, now_available, now_chosen, t.idx, t.key, t.bpm, cost, this_best_cost, kMixSongLen, this_best, its);

    if (this_best.size() > best.size()) {
      best = this_best;
      cout << "New OVERALL best of " << best.size() << " found!" << endl;
    }
    else if (this_best.size() == best.size() && this_best_cost < best_cost) {
      best_cost = this_best_cost;
      best = this_best;
      cout << "New OVERALL best cost of " << best_cost << " found!" << endl;
    }
  }

  // Show our results
  for (auto t : best) {
    cout
      << setw(3) << Key::GetShortName(t.key.num, t.key.type) << " @ "
      << setw(3) << static_cast<int>(t.bpm) << "bpm"
      << ", " << names[t.idx] << endl;
  }
  cout << "Cost is " << best_cost << endl;

  return EXIT_SUCCESS;

  //// Sort by BPM
  //sort(tracks.begin(), tracks.end(), [](Track const& a, Track const& b)
  //{
  //  return a.bpm < b.bpm;
  //});

  //// Interactive selection
  //vector<Track> order;
  //int idx = 0;

  //for (;;) {

  //  // Mark our work
  //  Track selected = tracks[idx];
  //  tracks.erase(tracks.begin() + idx);
  //  order.push_back(selected);

  //  cout << "Your current track: " << selected.name << endl;

  //  // Get options...
  //  vector<TrackOption> options;
  //  for (size_t i = 0; i < tracks.size(); ++i) {
  //    // Must be compatible
  //    if (!AreCompatibleKeys(selected.key, tracks[i].key)) {
  //      continue;
  //    }

  //    // Get the BPM ratio
  //    double bpm_ratio = max(selected.bpm, tracks[i].bpm) / min(selected.bpm, tracks[i].bpm);
  //    //double bpm_ratio_st = log(bpm_ratio) / log(Utils::GetSemitoneRatio());

  //    // We have an option
  //    TrackOption option(tracks[i], bpm_ratio, i);
  //    options.push_back(option);
  //  }

  //  // Sort by BPM ratio
  //  sort(options.begin(), options.end(), [](TrackOption const& a, TrackOption const& b) 
  //  {
  //    return a.bpm_ratio < b.bpm_ratio;
  //  }
  //  );

  //  // Print options
  //  cout << "Options: " << endl;
  //  for (size_t i = 0; i < options.size(); ++i) {
  //    cout << i << "\t" << fixed << setw(4) << options[i].bpm_ratio << "\t" << options[i].track.name << " (" << options[i].track.key.short_name << ")" << endl;
  //  }

  //  cout << "You have selected " << order.size() << " tracks" << endl;

  //  string choice;
  //  getline(cin, choice);

  //  if (!choice.compare("q")) {
  //    break;
  //  }

  //  stringstream ss(choice);
  //  ss >> idx;
  //  idx = options[idx].idx;
  //}

  //// Write our order
  //ofstream order_f("order.txt");
  //for (auto t : order) {
  //  order_f << t.bpm << "\t" << t.name << " (" << t.key.short_name << ")" << endl;
  //}
  //order_f.close();

  //// Start by just choosing a base track (try each one)
  //vector<Tracks> options;
  //// Our starting track
  //for (auto t : tracks) {
  //  cout << "Starting with " << t.name << endl;
  //  Tracks order;
  //  if (ChooseTrack(t, tracks, order)) {
  //    options.push_back(order);
  //    cout << "Found " << options.size() << " solutions!" << endl;
  //  }
  //}

  //// Select a key ordering
  //vector<Keys> options;
  //int max_depth = 0;
  //for (auto k : key_counts) {
  //  cout << "Starting with " << k.first.short_name << endl;
  //  Keys order;
  //  if (ChooseKey(KeyFromString("Dbm") /*k.first*/, key_counts, order, 1, max_depth)) {
  //    options.push_back(order);
  //    cout << "Found " << options.size() << " solutions!" << endl;
  //  }
  //}

  // Find a mix that works!
  MixAnt ma;
  Mix m = ma.FindMix(tracks);

  // Print the mix
  //cout << m << endl;

  cout << "Mix uses " << m.steps.size() << " of " << tracks.size() << " input tracks" << endl << endl;

  // Save the mix to a file
  ofstream ofs("mix.txt");
  ofs << m;
  ofs.close();

  // write our unused tracks
  Tracks unused(tracks);
  for (auto s : m.steps) {
    for (auto it = unused.begin(); it != unused.end(); ++it) {
      if (*it == s.track) {
        unused.erase(it);
        break;
      }
    }
  }
    
  ofstream unused_f("unused.txt");
  for (auto u : unused) {
    //unused_f << u.name << endl;
    //unused_f << u.key.short_name << endl;
    unused_f << u.bpm << endl;
  }
  unused_f.close();

  //cin.get();
}
Beispiel #2
0
 /** Returns the number of tracks. */
 size_t getNumberOfTracks() const { return m_tracks.size(); }
Beispiel #3
0
void ChooseTrack(
  vector<string> names,
  Tracks& available, 
  Tracks& chosen, 
  int prev_idx,
  Key prev_key, 
  double prev_bpm,
  double cost,
  double& best_cost,
  int max_len,
  Tracks& best,
  int& its
  )
{
  // We're too long!
  if (chosen.size() >= static_cast<size_t>(max_len)) {
    return;
  }

  // We have a new best length (more important than cost)
  if (chosen.size() > best.size()) {
    best_cost = cost;
    best = chosen;
    cout << "New best of length " << best.size() << " found." << endl;
    its = 0;
  } 
  // Mix length is the same, but less cost
  else if (chosen.size() == best.size() && cost < best_cost && !chosen.empty()) {
    best_cost = cost;
    cout << "New best cost of " << best_cost << " found." << endl;
    best = chosen;
    its = 0;
  }
  // No improvement!
  else {
    ++its;
  }

  // We've spent too long, so bail!
  if (its >= 1000000) {
    cout << "Too many iterations without improvement!" << endl;
    return;
  }

  // Nothing to look at
  if (available.empty()) {
    cout << "No more tracks to choose." << endl;
    return;
  }

  Track prev(prev_idx, prev_bpm, prev_key);

  // Go through all available and find those compatible
  Tracks candidates;
  Keys candidates_adj;
  vector<double> candidate_costs;

  for (auto t : available) {
    Key candidate_adj;
    double this_cost;
    if (AreCompatibleTracks(
      prev, 
      t, 
      kBPMThresh, 
      kKeyShiftThresh,
      candidate_adj,
      this_cost
      )) {
      candidates.push_back(t);
      candidates_adj.push_back(candidate_adj);
      candidate_costs.push_back(this_cost);
    }
  }

  for (size_t i = 0; i < candidates.size(); ++i) {
    Tracks now_available = available;
    Track t = candidates[i];
      
    // Erase the candidate from the now available list
    for (size_t j = 0; j < now_available.size(); ++j) {
      if (now_available[j] == t) {
        now_available.erase(now_available.begin() + j);
        break;
      }
    }

    // Set to our new key
    t.key = candidates_adj[i];

    Tracks now_chosen = chosen;
    now_chosen.push_back(t);

    // NOTE: We send in an ADJUSTED key for this track!
    ChooseTrack(names, now_available, now_chosen, t.idx, t.key, t.bpm, cost + candidate_costs[i], best_cost, max_len, best, its);
  }
}