recur_bin_slopes_new(const int n_bins, const int fft_len, const float fmin, const float fmax, const float fknee, const float ffocus, const float audio_rate){ const int n_slopes = n_bins + 1; RecurAudioBinSlope * slopes = malloc_aligned_or_die(n_slopes * sizeof(RecurAudioBinSlope)); int i; const float mmin = hz_to_mel(fmin, fknee, ffocus); const float mmax = hz_to_mel(fmax, fknee, ffocus); const float step = (mmax - mmin) / n_slopes; float hz_to_samples = fft_len * 2 / audio_rate; float hz = fmin; float mel = mmin; float right = hz * hz_to_samples; MAYBE_DEBUG("mmin %f mmax %f, fmin %f, fmax %f fknee %f ffocus %f", mmin, mmax, fmin, fmax, fknee, ffocus); for (i = 0; i < n_slopes; i++){ RecurAudioBinSlope *s = &slopes[i]; float left = right; s->left = (int)left; s->left_fraction = 1.0 - (left - s->left); mel += step; hz = mel_to_hz(mel, fknee, ffocus); right = hz * hz_to_samples; s->right = (int)right; s->right_fraction = right - s->right; s->slope = 1.0 / (right - left); if (s->left == s->right){ /*triangle is too little! */ s->left_fraction = (right - left); s->right_fraction = 0; } s->log_scale = logf(1.0f + right - left); MAYBE_DEBUG("slope %d: left %d+%.2f right %d+%.2f log_scale %f hz %f" " mel %f mmin %f mmax %f", i, s->left, s->left_fraction, s->right, s->right_fraction, s->log_scale, hz, mel, mmin, mmax); } return slopes; }
static inline float mel_to_hz(float mel, float knee, float focus){ float hz = (mel / 34) * (mel / 34); float approx; float prev = hz_to_mel(hz, knee, focus) - 1; float mul = 2.0f; for (;;){ approx = hz_to_mel(hz, knee, focus); MAYBE_DEBUG("mel %f approx %f prev %f diff %g mul %f hz %f", mel, approx, prev, approx - mel, mul, hz); if (fabs(mel - approx) < 0.0001 || prev == approx){ return hz; } hz = MAX(hz + mul * (mel - approx), 0); if ((prev > mel) != (approx > mel)){ mul *= 0.5; } prev = approx; } }
bool RoomAndCorridorMap::TryBuildMap(const Point& size, bool verbose) { size_ = size; tileset_.reset(new DefaultTileset()); Level level(size_); vector<Rect> rects; const int min_size = 6; const int max_size = 8; const int separation = 3; const int tries = size_.x*size_.y/(min_size*min_size); int tries_left = tries; while (tries_left > 0) { const Point size{RandInt(min_size, max_size), RandInt(min_size/2, max_size/2)}; const Rect rect{size, {RandInt(1, size_.x - size.x - 1), RandInt(1, size_.y - size.y - 1)}}; if (!level.PlaceRectangularRoom(rect, separation, &rects)) { tries_left -= 1; } } const int n = rects.size(); ASSERT(n > 0); MAYBE_DEBUG("Placed " << IntToString(n) << " rectangular rooms after " << IntToString(tries) << " attempts."); Array2d<double> graph = ConstructArray2d<double>(Point(n, n), 0); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { graph[i][j] = RectToRectDistance(rects[i], rects[j]); ASSERT((i == j) == (graph[i][j] == 0)); } } vector<Point> edges = MinimumSpanningTree(graph); MAYBE_DEBUG("Computed a minimal spanning tree with " << IntToString(edges.size()) << " edges."); int loop_edges = 0; Array2d<double> distances = ComputeTreeDistances(graph, edges); while (true) { Point best_edge; double best_ratio = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { double ratio = distances[i][j]/graph[i][j]; if (ratio > best_ratio) { best_edge = Point(i, j); best_ratio = ratio; } } } if (best_ratio < 2.0) { break; } edges.push_back(best_edge); double distance = graph[best_edge.x][best_edge.y]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { distances[i][j] = min(distances[i][j], min( distances[i][best_edge.x] + distance + distances[best_edge.y][j], distances[i][best_edge.y] + distance + distances[best_edge.x][j])); } } loop_edges += 1; } MAYBE_DEBUG("Added " << IntToString(loop_edges) << " high-ratio loop edges."); const double islandness = rand() % 3; for (int i = 0; i < 3; i++) { level.Erode(islandness); } level.ExtractFinalRooms(n, &rooms_); const double windiness = 1.0; for (const Point& edge : edges) { ASSERT(edge.x != edge.y); if (!level.DigCorridor(rooms_, edge.x, edge.y, windiness)) { MAYBE_DEBUG("Failed to dig corridor. Retrying..."); return false; } } MAYBE_DEBUG("Dug " << IntToString(edges.size()) << " corridors."); level.AddWalls(); starting_square_ = rooms_[0].GetRandomSquare(); MAYBE_DEBUG("Final map:" << level.ToDebugString()); PackTiles(level.tiles); return true; }
/*mfcc_slopes_dump draws a PGM showing whether the slope calculations worked*/ static void mfcc_slopes_dump(RecurAudioBinner *ab){ int i, j; int wsize = ab->window_size / ab->value_size; u8 *img = malloc_aligned_or_die(ab->n_bins * wsize); memset(img, 0, ab->n_bins * wsize); float mul; RecurAudioBinSlope *slope; /*first slope is left side only, last slope is right only*/ for (i = 0; i <= ab->n_bins; i++){ u8 *left = (i < ab->n_bins) ? img + i * wsize : NULL; u8 *right = (i) ? img + (i - 1) * wsize : NULL; slope = &ab->slopes[i]; float sum_left = 0.0; float sum_right = 0.0; /*left fractional part*/ mul = slope->slope * slope->left_fraction; if (left){ left[slope->left] += 255 * mul * slope->left_fraction; sum_left += mul * slope->left_fraction; } if (right){ right[slope->left] += 255 * (1.0 - mul) * slope->left_fraction; sum_right += (1.0 - mul) * slope->left_fraction; } if (slope->left != slope->right){ /*centre */ for (j = slope->left + 1; j < slope->right; j++){ mul += slope->slope; if (left){ left[j] += mul * 255; sum_left += mul; } if (right){ right[j] += (1.0 - mul) * 255; sum_right += (1.0 - mul); } } } /*right fraction */ mul += slope->slope * slope->right_fraction; if (left){ left[slope->right] += 255 * mul * slope->right_fraction; sum_left += mul * slope->right_fraction; } if (right){ right[slope->right] += 255 * (1.0f - mul) * slope->right_fraction; sum_right += (1.0f - mul) * slope->right_fraction; } MAYBE_DEBUG("%2d. left%3d right%3d slope %.3f fractions: L %.3f R %.3f mul at end %.3f" " sum_L %.3f sum_R %.3f sum %.3f", i, slope->left, slope->right, slope->slope, slope->left_fraction, slope->right_fraction, mul, sum_left, sum_right, sum_left + sum_right); } pgm_dump(img, wsize, ab->n_bins, IMAGE_DIR "/mfcc-bins.pgm"); free(img); }