From: Jean-Baptiste Mardelle Date: Mon, 12 Nov 2012 01:19:26 +0000 (+0100) Subject: Rewrite parts of audio thumbnail. We now use square root for better thumbs, now looks... X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=2947837eeebe0349551ecc4790672d2a254d3370;p=kdenlive Rewrite parts of audio thumbnail. We now use square root for better thumbs, now looks much more like Audacity, also fix when zooming. --- diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 8670aed3..fcae1feb 100644 --- a/src/clipitem.cpp +++ b/src/clipitem.cpp @@ -889,8 +889,8 @@ void ClipItem::paint(QPainter *painter, } for (int startCache = mappedStartPixel - (mappedStartPixel) % 100; startCache < mappedEndPixel; startCache += 100) { - if (m_audioThumbCachePic.contains(startCache) && !m_audioThumbCachePic[startCache].isNull()) - painter->drawPixmap(clipStart + startCache - cropLeft, mappedRect.y(), m_audioThumbCachePic[startCache]); + if (!m_audioThumbCachePic.value(startCache).isNull()) + painter->drawPixmap(clipStart + startCache - cropLeft, mappedRect.y(), m_audioThumbCachePic.value(startCache)); } } @@ -1101,87 +1101,107 @@ QList ClipItem::commentedSnapMarkers() const void ClipItem::slotPrepareAudioThumb(double pixelForOneFrame, int startpixel, int endpixel, int channels) { + // Bail out, if caller provided invalid data + if (channels <= 0) { + kWarning() << "Unable to draw image with " << channels << "number of channels"; + return; + } QRectF re = sceneBoundingRect(); if (m_clipType == AV && !isAudioOnly()) re.setTop(re.y() + re.height() / 2); + int factor = 64; + if (KdenliveSettings::normaliseaudiothumbs()) { + factor = m_clip->getProperty("audio_max").toInt(); + } //kDebug() << "// PREP AUDIO THMB FRMO : scale:" << pixelForOneFrame<< ", from: " << startpixel << ", to: " << endpixel; //if ( (!audioThumbWasDrawn || framePixelWidth!=pixelForOneFrame ) && !baseClip()->audioFrameChache.isEmpty()){ + bool fullAreaDraw = pixelForOneFrame < 10; + bool simplifiedAudio = !KdenliveSettings::displayallchannels(); + QPen audiopen; + audiopen.setWidth(0); + if (simplifiedAudio) channels = 1; + int channelHeight = re.height() / channels; + QMap positiveChannelPaths; + QMap negativeChannelPaths; for (int startCache = startpixel - startpixel % 100; startCache < endpixel; startCache += 100) { - //kDebug() << "creating " << startCache; - //if (framePixelWidth!=pixelForOneFrame || if (m_framePixelWidth == pixelForOneFrame && m_audioThumbCachePic.contains(startCache)) continue; - if (m_audioThumbCachePic[startCache].isNull() || m_framePixelWidth != pixelForOneFrame) { - m_audioThumbCachePic[startCache] = QPixmap(100, (int)(re.height())); - m_audioThumbCachePic[startCache].fill(QColor(180, 180, 200, 140)); + if (m_audioThumbCachePic.value(startCache).isNull() || m_framePixelWidth != pixelForOneFrame) { + QPixmap pix(100, (int)(re.height())); + pix.fill(QColor(180, 180, 180, 150)); + m_audioThumbCachePic[startCache] = pix; } - bool fullAreaDraw = pixelForOneFrame < 10; - QMap positiveChannelPaths; - QMap negativeChannelPaths; + positiveChannelPaths.clear(); + negativeChannelPaths.clear(); + QPainter pixpainter(&m_audioThumbCachePic[startCache]); - QPen audiopen; - audiopen.setWidth(0); - pixpainter.setPen(audiopen); - //pixpainter.setRenderHint(QPainter::Antialiasing,true); - //pixpainter.drawLine(0,0,100,re.height()); - // Bail out, if caller provided invalid data - if (channels <= 0) { - kWarning() << "Unable to draw image with " << channels << "number of channels"; - return; - } - - int channelHeight = m_audioThumbCachePic[startCache].height() / channels; - for (int i = 0; i < channels; i++) { - - positiveChannelPaths[i].moveTo(0, channelHeight*i + channelHeight / 2); - negativeChannelPaths[i].moveTo(0, channelHeight*i + channelHeight / 2); - } + for (int i = 0; i < channels; i++) { + if (simplifiedAudio) { + positiveChannelPaths[i].moveTo(-1, channelHeight); + } + else if (fullAreaDraw) { + positiveChannelPaths[i].moveTo(-1, channelHeight*i + channelHeight / 2); + negativeChannelPaths[i].moveTo(-1, channelHeight*i + channelHeight / 2); + } + else { + positiveChannelPaths[i].moveTo(-1, channelHeight*i + channelHeight / 2); + audiopen.setColor(QColor(60, 60, 60, 50)); + pixpainter.setPen(audiopen); + pixpainter.drawLine(0, channelHeight*i + channelHeight / 2, 100, channelHeight*i + channelHeight / 2); + } + } for (int samples = 0; samples <= 100; samples++) { double frame = (double)(samples + startCache - 0) / pixelForOneFrame; int sample = (int)((frame - (int)(frame)) * 20); // AUDIO_FRAME_SIZE if (frame < 0 || sample < 0 || sample > 19) continue; - QMap frame_channel_data = baseClip()->audioFrameCache[(int)frame]; - - for (int channel = 0; channel < channels && frame_channel_data[channel].size() > 0; channel++) { - - int y = channelHeight * channel + channelHeight / 2; - int delta = (int)(frame_channel_data[channel][sample] - 127 / 2) * channelHeight / 64; - if (fullAreaDraw) { - positiveChannelPaths[channel].lineTo(samples, 0.1 + y + qAbs(delta)); - negativeChannelPaths[channel].lineTo(samples, 0.1 + y - qAbs(delta)); + const QMap frame_channel_data = baseClip()->audioFrameCache.value((int)frame); + + for (int channel = 0; channel < channels && !frame_channel_data.value(channel).isEmpty(); channel++) { + int y = channelHeight * channel + channelHeight / 2; + if (simplifiedAudio) { + double delta = qAbs((frame_channel_data.value(channel).at(sample) - 63.5) * channelHeight / factor); + positiveChannelPaths[channel].lineTo(samples, channelHeight - delta); + } else if (fullAreaDraw) { + double delta = qAbs((frame_channel_data.value(channel).at(sample) - 63.5) * channelHeight / (2 * factor)); + positiveChannelPaths[channel].lineTo(samples, y + delta); + negativeChannelPaths[channel].lineTo(samples, y - delta); } else { - positiveChannelPaths[channel].lineTo(samples, 0.1 + y + delta); - negativeChannelPaths[channel].lineTo(samples, 0.1 + y - delta); + double delta = (frame_channel_data.value(channel).at(sample) - 63.5) * channelHeight / (2 * factor); + positiveChannelPaths[channel].lineTo(samples, y + delta); } } - for (int channel = 0; channel < channels ; channel++) - if (fullAreaDraw && samples == 100) { - positiveChannelPaths[channel].lineTo(samples, channelHeight*channel + channelHeight / 2); - negativeChannelPaths[channel].lineTo(samples, channelHeight*channel + channelHeight / 2); - positiveChannelPaths[channel].lineTo(0, channelHeight*channel + channelHeight / 2); - negativeChannelPaths[channel].lineTo(0, channelHeight*channel + channelHeight / 2); - } - } - pixpainter.setPen(QPen(QColor(0, 0, 0))); - pixpainter.setBrush(QBrush(QColor(60, 60, 60))); - + for (int channel = 0; channel < channels; channel++) { + if (simplifiedAudio) { + positiveChannelPaths[channel].lineTo(101, channelHeight); + } else if (fullAreaDraw) { + int y = channelHeight * channel + channelHeight / 2; + positiveChannelPaths[channel].lineTo(101, y); + negativeChannelPaths[channel].lineTo(101, y); + } + } + if (fullAreaDraw || simplifiedAudio) { + audiopen.setColor(QColor(80, 80, 80, 200)); + pixpainter.setPen(audiopen); + pixpainter.setBrush(QBrush(QColor(120, 120, 120, 200))); + } + else { + audiopen.setColor(QColor(60, 60, 60, 100)); + pixpainter.setPen(audiopen); + pixpainter.setBrush(Qt::NoBrush); + } for (int i = 0; i < channels; i++) { if (fullAreaDraw) { - //pixpainter.fillPath(positiveChannelPaths[i].united(negativeChannelPaths[i]),QBrush(Qt::SolidPattern));//or singleif looks better - pixpainter.drawPath(positiveChannelPaths[i].united(negativeChannelPaths[i]));//or singleif looks better + pixpainter.drawPath(positiveChannelPaths[i].united(negativeChannelPaths.value(i))); } else - pixpainter.drawPath(positiveChannelPaths[i]); + pixpainter.drawPath(positiveChannelPaths.value(i)); } } - //audioThumbWasDrawn=true; m_framePixelWidth = pixelForOneFrame; - - //} } int ClipItem::fadeIn() const diff --git a/src/clipmanager.cpp b/src/clipmanager.cpp index a706e5ad..f652fcbc 100644 --- a/src/clipmanager.cpp +++ b/src/clipmanager.cpp @@ -252,7 +252,7 @@ void ClipManager::askForAudioThumb(const QString &id) void ClipManager::slotGetAudioThumbs() { Mlt::Profile prof((char*) KdenliveSettings::current_profile().toUtf8().constData()); - mlt_audio_format audioFormat = mlt_audio_pcm; + mlt_audio_format audioFormat = mlt_audio_s16; while (!m_abortAudioThumb && !m_audioThumbsQueue.isEmpty()) { m_thumbsMutex.lock(); m_processingAudioThumbId = m_audioThumbsQueue.takeFirst(); @@ -264,11 +264,15 @@ void ClipManager::slotGetAudioThumbs() if (hash.isEmpty()) continue; QString audioPath = projectFolder() + "/thumbs/" + hash + ".thumb"; double lengthInFrames = clip->duration().frames(m_doc->fps()); - //FIXME: should this be hardcoded?? - int channels = 2; - int frequency = 48000; - int arrayWidth = 20; + int frequency = 48000; + int channels = 2; + QString data = clip->getProperty("frequency"); + if (!data.isEmpty()) frequency = data.toInt(); + data = clip->getProperty("channels"); + if (!data.isEmpty()) channels = data.toInt(); + int arrayWidth = 20; double frame = 0.0; + int maxVolume = 0; audioByteArray storeIn; QFile f(audioPath); if (QFileInfo(audioPath).size() > 0 && f.open(QIODevice::ReadOnly)) { @@ -290,13 +294,17 @@ void ClipManager::slotGetAudioThumbs() QByteArray audioArray(arrayWidth, '\x00'); for (int i = 0; i < arrayWidth; i++) { audioArray[i] = channelarray.at(h2 + h3 + i); + if (audioArray.at(i) > maxVolume) maxVolume = audioArray.at(i); } h3 += arrayWidth; storeIn[z][c] = audioArray; } h2 += h1; } - if (!m_abortAudioThumb) clip->updateAudioThumbnail(storeIn); + if (!m_abortAudioThumb) { + clip->setProperty("audio_max", QString::number(maxVolume - 64)); + clip->updateAudioThumbnail(storeIn); + } continue; } @@ -319,9 +327,9 @@ void ClipManager::slotGetAudioThumbs() producer.set("video_index", "-1"); if (KdenliveSettings::normaliseaudiothumbs()) { - Mlt::Filter m_convert(prof, "volume"); + /*Mlt::Filter m_convert(prof, "volume"); m_convert.set("gain", "normalise"); - producer.attach(m_convert); + producer.attach(m_convert);*/ } int last_val = 0; @@ -344,7 +352,17 @@ void ClipManager::slotGetAudioThumbs() QByteArray audioArray; audioArray.resize(arrayWidth); for (int i = 0; i < audioArray.size(); i++) { - audioArray[i] = ((*(pcm + c + i * samples / audioArray.size())) >> 9) + 127 / 2 ; + double pcmval = *(pcm + c + i * samples / audioArray.size()); + if (pcmval >= 0) { + pcmval = sqrt(pcmval) / 2.83 + 64; + audioArray[i] = pcmval; + if (pcmval > maxVolume) maxVolume = pcmval; + } + else { + pcmval = -sqrt(-pcmval) / 2.83 + 64; + audioArray[i] = pcmval; + if (-pcmval > maxVolume) maxVolume = -pcmval; + } } f.write(audioArray); storeIn[z][c] = audioArray; @@ -360,6 +378,7 @@ void ClipManager::slotGetAudioThumbs() f.remove(); } else { clip->updateAudioThumbnail(storeIn); + clip->setProperty("audio_max", QString::number(maxVolume - 64)); } } m_processingAudioThumbId.clear(); diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index b6044801..4726b1f2 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -155,6 +155,11 @@ false + + + true + + true diff --git a/src/widgets/configtimeline_ui.ui b/src/widgets/configtimeline_ui.ui index 33d42221..fe0aea0e 100644 --- a/src/widgets/configtimeline_ui.ui +++ b/src/widgets/configtimeline_ui.ui @@ -6,7 +6,7 @@ 0 0 - 281 + 361 222 @@ -39,8 +39,21 @@ + + + + false + + + Channels + + + + + false + Normalise audio for thumbnails @@ -129,5 +142,38 @@ - + + + kcfg_audiothumbnails + toggled(bool) + kcfg_normaliseaudiothumbs + setEnabled(bool) + + + 35 + 66 + + + 208 + 66 + + + + + kcfg_audiothumbnails + toggled(bool) + kcfg_displayallchannels + setEnabled(bool) + + + 35 + 66 + + + 105 + 66 + + + +