From: Jean-Baptiste M. <jb...@kd...> - 2012-11-12 01:20:09
|
Git commit 2947837eeebe0349551ecc4790672d2a254d3370 by Jean-Baptiste Mardelle. Committed on 12/11/2012 at 02:19. Pushed by mardelle into branch 'master'. Rewrite parts of audio thumbnail. We now use square root for better thumbs, now looks much more like Audacity, also fix when zooming. M +75 -55 src/clipitem.cpp M +28 -9 src/clipmanager.cpp M +5 -0 src/kdenlivesettings.kcfg M +48 -2 src/widgets/configtimeline_ui.ui http://commits.kde.org/kdenlive/2947837eeebe0349551ecc4790672d2a254d3370 diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 8670aed..fcae1fe 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 <CommentedTime> 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<int, QPainterPath > positiveChannelPaths; + QMap<int, QPainterPath > 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<int, QPainterPath > positiveChannelPaths; - QMap<int, QPainterPath > 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<int, QByteArray> 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<int, QByteArray> 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 a706e5a..f652fcb 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 b604480..4726b1f 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -155,6 +155,11 @@ <default>false</default> </entry> + <entry name="displayallchannels" type="Bool"> + <label>Display all channels in audio thumbnails.</label> + <default>true</default> + </entry> + <entry name="normaliseaudiothumbs" type="Bool"> <label>Normalise audio before creating thumbnails.</label> <default>true</default> diff --git a/src/widgets/configtimeline_ui.ui b/src/widgets/configtimeline_ui.ui index 33d4222..fe0aea0 100644 --- a/src/widgets/configtimeline_ui.ui +++ b/src/widgets/configtimeline_ui.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>281</width> + <width>361</width> <height>222</height> </rect> </property> @@ -40,7 +40,20 @@ </widget> </item> <item> + <widget class="QCheckBox" name="kcfg_displayallchannels"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Channels</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="kcfg_normaliseaudiothumbs"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="text"> <string>Normalise audio for thumbnails</string> </property> @@ -129,5 +142,38 @@ </layout> </widget> <resources/> - <connections/> + <connections> + <connection> + <sender>kcfg_audiothumbnails</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_normaliseaudiothumbs</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>35</x> + <y>66</y> + </hint> + <hint type="destinationlabel"> + <x>208</x> + <y>66</y> + </hint> + </hints> + </connection> + <connection> + <sender>kcfg_audiothumbnails</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_displayallchannels</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>35</x> + <y>66</y> + </hint> + <hint type="destinationlabel"> + <x>105</x> + <y>66</y> + </hint> + </hints> + </connection> + </connections> </ui> |