void BlockAnalyzer::transform( Analyzer::Scope &s ) //pure virtual { for( uint x = 0; x < s.size(); ++x ) s[x] *= 2; float *front = static_cast<float*>( &s.front() ); m_fht->spectrum( front ); m_fht->scale( front, 1.0 / 20 ); //the second half is pretty dull, so only show it if the user has a large analyzer //by setting to m_scope.size() if large we prevent interpolation of large analyzers, this is good! s.resize( m_scope.size() <= MAX_COLUMNS/2 ? MAX_COLUMNS/2 : m_scope.size() ); }
void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_frame) { // Discard the second half of the transform const int scope_size = s.size() / 2; if ((new_frame && is_playing_) || (buffer_[0].isNull() && buffer_[1].isNull())) { // Transform the music into rainbows! for (int band = 0; band < kRainbowBands; ++band) { float* band_start = history_ + band * kHistorySize; // Move the history of each band across by 1 frame. memmove(band_start, band_start + 1, (kHistorySize - 1) * sizeof(float)); } // Now accumulate the scope data into each band. Should maybe use a series // of band pass filters for this, so bands can leak into neighbouring bands, // but for now it's a series of separate square filters. const int samples_per_band = scope_size / kRainbowBands; int sample = 0; for (int band = 0; band < kRainbowBands; ++band) { float accumulator = 0.0; for (int i = 0; i < samples_per_band; ++i) { accumulator += s[sample++]; } history_[(band + 1) * kHistorySize - 1] = accumulator * band_scale_[band]; } // Create polylines for the rainbows. QPointF polyline[kRainbowBands * kHistorySize]; QPointF* dest = polyline; float* source = history_; const float top_of_cat = float(height()) / 2 - float(kCatHeight) / 2; for (int band = 0; band < kRainbowBands; ++band) { // Calculate the Y position of this band. const float y = float(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat; // Add each point in the line. for (int x = 0; x < kHistorySize; ++x) { *dest = QPointF(px_per_frame_ * x, y + *source * kPixelScale); ++dest; ++source; } } // Do we have to draw the whole rainbow into the buffer? if (buffer_[0].isNull()) { for (int i = 0; i < 2; ++i) { buffer_[i] = QPixmap(QSize(width() + x_offset_, height())); buffer_[i].fill(background_brush_.color()); } current_buffer_ = 0; QPainter buffer_painter(&buffer_[0]); buffer_painter.setRenderHint(QPainter::Antialiasing); for (int band = kRainbowBands - 1; band >= 0; --band) { buffer_painter.setPen(colors_[band]); buffer_painter.drawPolyline(&polyline[band * kHistorySize], kHistorySize); buffer_painter.drawPolyline(&polyline[band * kHistorySize], kHistorySize); } } else { const int last_buffer = current_buffer_; current_buffer_ = (current_buffer_ + 1) % 2; // We can just shuffle the buffer along a bit and draw the new frame's // data. QPainter buffer_painter(&buffer_[current_buffer_]); buffer_painter.setRenderHint(QPainter::Antialiasing); buffer_painter.drawPixmap( 0, 0, buffer_[last_buffer], px_per_frame_, 0, x_offset_ + available_rainbow_width_ - px_per_frame_, 0); buffer_painter.fillRect( x_offset_ + available_rainbow_width_ - px_per_frame_, 0, kCatWidth - kRainbowOverlap + px_per_frame_, height(), background_brush_); for (int band = kRainbowBands - 1; band >= 0; --band) { buffer_painter.setPen(colors_[band]); buffer_painter.drawPolyline(&polyline[(band + 1) * kHistorySize - 3], 3); } } } // Draw the buffer on to the widget p.drawPixmap(0, 0, buffer_[current_buffer_], x_offset_, 0, 0, 0); // Draw nyan cat (he's been waiting for this for 75 lines). // Nyan nyan nyan nyan. if (!is_playing_) { // Ssshhh! p.drawPixmap(SleepingCatDestRect(), cat_, SleepingCatSourceRect()); } else { p.drawPixmap(CatDestRect(), cat_, CatSourceRect()); } }