Audio playback seek feature (#1520)

presentation
morrolinux 6 years ago committed by Ulrich Huber
parent ce92bb0621
commit fe44da3ea4
  1. 10
      src/control/AudioController.cpp
  2. 2
      src/control/AudioController.h
  3. 8
      src/control/Control.cpp
  4. 21
      src/control/settings/Settings.cpp
  5. 8
      src/control/settings/Settings.h
  6. 2
      src/enums/ActionType.enum.h
  7. 20
      src/enums/generated/ActionType.generated.cpp
  8. 2
      src/gui/dialog/SettingsDialog.cpp
  9. 12
      src/gui/toolbarMenubar/ToolMenuHandler.cpp
  10. 2
      src/gui/toolbarMenubar/ToolMenuHandler.h
  11. 6
      src/util/audio/AudioPlayer.cpp
  12. 1
      src/util/audio/AudioPlayer.h
  13. 17
      src/util/audio/VorbisProducer.cpp
  14. 3
      src/util/audio/VorbisProducer.h
  15. BIN
      ui/icons/hicolor/icon-theme.cache
  16. 6
      ui/icons/hicolor/scalable/actions/audio-seek-backwards.svg
  17. 6
      ui/icons/hicolor/scalable/actions/audio-seek-forwards.svg
  18. 23
      ui/main.glade
  19. 74
      ui/settings.glade
  20. 4
      ui/toolbar.ini

@ -100,6 +100,16 @@ void AudioController::pausePlayback()
this->audioPlayer->pause();
}
void AudioController::seekForwards()
{
this->audioPlayer->seek(this->settings->getDefaultSeekTime());
}
void AudioController::seekBackwards()
{
this->audioPlayer->seek(-1 * this->settings->getDefaultSeekTime());
}
void AudioController::continuePlayback()
{
this->control->getWindow()->getToolMenuHandler()->setAudioPlaybackPaused(false);

@ -35,6 +35,8 @@ public:
void pausePlayback();
void continuePlayback();
void stopPlayback();
void seekForwards();
void seekBackwards();
string getAudioFilename();
Path getAudioFolder();

@ -1003,6 +1003,14 @@ void Control::actionPerformed(ActionType type, ActionGroup group, GdkEvent* even
}
break;
case ACTION_AUDIO_SEEK_FORWARDS:
this->getAudioController()->seekForwards();
break;
case ACTION_AUDIO_SEEK_BACKWARDS:
this->getAudioController()->seekBackwards();
break;
case ACTION_AUDIO_STOP_PLAYBACK:
this->getAudioController()->stopPlayback();
break;

@ -135,6 +135,7 @@ void Settings::loadDefault()
this->audioInputDevice = -1;
this->audioOutputDevice = -1;
this->audioGain = 1.0;
this->defaultSeekTime = 5;
this->pluginEnabled = "";
this->pluginDisabled = "";
@ -564,6 +565,10 @@ void Settings::parseItem(xmlDocPtr doc, xmlNodePtr cur)
{
this->audioGain = tempg_ascii_strtod((const char *) value, nullptr);
}
else if (xmlStrcmp(name, (const xmlChar*) "defaultSeekTime") == 0)
{
this->defaultSeekTime = tempg_ascii_strtod((const char *) value, nullptr);
}
else if (xmlStrcmp(name, (const xmlChar*) "audioInputDevice") == 0)
{
this->audioInputDevice = g_ascii_strtoll((const char *) value, nullptr, 10);
@ -996,6 +1001,7 @@ void Settings::save()
WRITE_INT_PROP(audioOutputDevice);
WRITE_DOUBLE_PROP(audioSampleRate);
WRITE_DOUBLE_PROP(audioGain);
WRITE_INT_PROP(defaultSeekTime);
WRITE_STRING_PROP(pluginEnabled);
WRITE_STRING_PROP(pluginDisabled);
@ -2066,6 +2072,21 @@ void Settings::setAudioGain(double gain)
save();
}
unsigned int Settings::getDefaultSeekTime() const
{
return this->defaultSeekTime;
}
void Settings::setDefaultSeekTime(unsigned int t)
{
if (this->defaultSeekTime == t)
{
return;
}
this->defaultSeekTime = t;
save();
}
string const& Settings::getPluginEnabled() const
{
return this->pluginEnabled;

@ -356,6 +356,9 @@ public:
double getAudioGain() const;
void setAudioGain(double gain);
unsigned int getDefaultSeekTime() const;
void setDefaultSeekTime(unsigned int t);
string const& getPluginEnabled() const;
void setPluginEnabled(string pluginEnabled);
@ -786,6 +789,11 @@ private:
*/
double audioGain;
/**
* The default time by which the playback will seek backwards and forwards
*/
unsigned int defaultSeekTime;
/**
* List of enabled plugins (only the one which are not enabled by default)
*/

@ -164,6 +164,8 @@ enum ActionType
ACTION_AUDIO_RECORD,
ACTION_AUDIO_PAUSE_PLAYBACK,
ACTION_AUDIO_STOP_PLAYBACK,
ACTION_AUDIO_SEEK_FORWARDS,
ACTION_AUDIO_SEEK_BACKWARDS,
ACTION_SET_PAIRS_OFFSET,
ACTION_SET_COLUMNS,
ACTION_SET_COLUMNS_1,

@ -552,6 +552,16 @@ ActionType ActionType_fromString(string value)
return ACTION_AUDIO_STOP_PLAYBACK;
}
if (value == "ACTION_AUDIO_SEEK_FORWARDS")
{
return ACTION_AUDIO_SEEK_FORWARDS;
}
if (value == "ACTION_AUDIO_SEEK_BACKWARDS")
{
return ACTION_AUDIO_SEEK_BACKWARDS;
}
if (value == "ACTION_SET_PAIRS_OFFSET")
{
return ACTION_SET_PAIRS_OFFSET;
@ -1255,6 +1265,16 @@ string ActionType_toString(ActionType value)
return "ACTION_AUDIO_STOP_PLAYBACK";
}
if (value == ACTION_AUDIO_SEEK_FORWARDS)
{
return "ACTION_AUDIO_SEEK_FORWARDS";
}
if (value == ACTION_AUDIO_SEEK_BACKWARDS)
{
return "ACTION_AUDIO_SEEK_BACKWARDS";
}
if (value == ACTION_SET_PAIRS_OFFSET)
{
return "ACTION_SET_PAIRS_OFFSET";

@ -414,6 +414,7 @@ void SettingsDialog::load()
}
gtk_spin_button_set_value(GTK_SPIN_BUTTON(get("spAudioGain")), settings->getAudioGain());
gtk_spin_button_set_value(GTK_SPIN_BUTTON(get("spDefaultSeekTime")), settings->getDefaultSeekTime());
}
string SettingsDialog::updateHideString(const string& hidden, bool hideMenubar, bool hideSidebar)
@ -641,6 +642,7 @@ void SettingsDialog::save()
}
settings->setAudioGain((double)gtk_spin_button_get_value(GTK_SPIN_BUTTON(get("spAudioGain"))));
settings->setDefaultSeekTime((double)gtk_spin_button_get_value(GTK_SPIN_BUTTON(get("spDefaultSeekTime"))));
for (DeviceClassConfigGui* deviceClassConfigGui : this->deviceClassConfigs)
{

@ -458,6 +458,10 @@ void ToolMenuHandler::initToolItems()
addToolItem(audioPausePlaybackButton);
audioStopPlaybackButton = new ToolButton(listener, "AUDIO_STOP_PLAYBACK", ACTION_AUDIO_STOP_PLAYBACK, "audio-playback-stop", _("Stop"));
addToolItem(audioStopPlaybackButton);
audioSeekForwardsButton = new ToolButton(listener, "AUDIO_SEEK_FORWARDS", ACTION_AUDIO_SEEK_FORWARDS, "audio-seek-forwards", _("Forward"));
addToolItem(audioSeekForwardsButton);
audioSeekBackwardsButton = new ToolButton(listener, "AUDIO_SEEK_BACKWARDS", ACTION_AUDIO_SEEK_BACKWARDS, "audio-seek-backwards", _("Back"));
addToolItem(audioSeekBackwardsButton);
// Menu Help
// ************************************************************************
@ -569,18 +573,26 @@ void ToolMenuHandler::disableAudioPlaybackButtons()
this->audioPausePlaybackButton->enable(false);
this->audioStopPlaybackButton->enable(false);
this->audioSeekBackwardsButton->enable(false);
this->audioSeekForwardsButton->enable(false);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioPausePlayback")), false);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioStopPlayback")), false);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioSeekForwards")), false);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioSeekBackwards")), false);
}
void ToolMenuHandler::enableAudioPlaybackButtons()
{
this->audioPausePlaybackButton->enable(true);
this->audioStopPlaybackButton->enable(true);
this->audioSeekBackwardsButton->enable(true);
this->audioSeekForwardsButton->enable(true);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioPausePlayback")), true);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioStopPlayback")), true);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioSeekForwards")), true);
gtk_widget_set_sensitive(GTK_WIDGET(gui->get("menuAudioSeekBackwards")), true);
}
void ToolMenuHandler::setAudioPlaybackPaused(bool paused)

@ -97,6 +97,8 @@ private:
ToolButton* audioPausePlaybackButton = nullptr;
ToolButton* audioStopPlaybackButton = nullptr;
ToolButton* audioSeekBackwardsButton = nullptr;
ToolButton* audioSeekForwardsButton = nullptr;
ToolPageSpinner* toolPageSpinner = nullptr;
ToolPageLayer* toolPageLayer = nullptr;

@ -84,6 +84,12 @@ void AudioPlayer::stop()
this->audioQueue->reset();
}
void AudioPlayer::seek(int seconds)
{
// set seek flag here in vorbisProducer
this->vorbisProducer->seek(seconds);
}
vector<DeviceInfo> AudioPlayer::getOutputDevices()
{
std::list<DeviceInfo> deviceList = this->portAudioConsumer->getOutputDevices();

@ -30,6 +30,7 @@ public:
void stop();
bool play();
void pause();
void seek(int seconds);
vector<DeviceInfo> getOutputDevices();

@ -20,6 +20,7 @@ bool VorbisProducer::start(std::string filename, unsigned int timestamp)
}
sf_count_t seekPosition = this->sfInfo.samplerate / 1000 * timestamp;
if (seekPosition < this->sfInfo.frames)
{
sf_seek(this->sfFile, seekPosition, SEEK_SET);
@ -37,16 +38,22 @@ bool VorbisProducer::start(std::string filename, unsigned int timestamp)
size_t numFrames = 1;
auto sampleBuffer = new float[1024 * this->sfInfo.channels];
std::unique_lock<std::mutex> lock(audioQueue->syncMutex());
while (!this->stopProducer && numFrames > 0 && !this->audioQueue->hasStreamEnded())
{
numFrames = sf_readf_float(this->sfFile, sampleBuffer, 1024);
numFrames = sf_readf_float(this->sfFile, sampleBuffer, 1024);
while (this->audioQueue->size() >= this->sample_buffer_size && !this->audioQueue->hasStreamEnded() && !this->stopProducer)
{
audioQueue->waitForConsumer(lock);
}
if (this->seekSeconds != 0)
{
sf_seek(this->sfFile,seekSeconds * this->sfInfo.samplerate, SEEK_CUR);
this->seekSeconds = 0;
}
this->audioQueue->push(sampleBuffer, static_cast<size_t>(numFrames * this->sfInfo.channels));
}
this->audioQueue->signalEndOfStream();
@ -76,3 +83,9 @@ void VorbisProducer::stop()
this->producerThread->join();
}
}
void VorbisProducer::seek(int seconds)
{
this->seekSeconds = seconds;
}

@ -31,6 +31,7 @@ public:
bool start(string filename, unsigned int timestamp);
void abort();
void stop();
void seek(int seconds);
private:
const int sample_buffer_size = 16384;
@ -41,4 +42,6 @@ private:
AudioQueue<float>* audioQueue = nullptr;
std::thread* producerThread = nullptr;
int seekSeconds = 0;
};

Binary file not shown.

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="22pt" height="22pt" viewBox="0 0 22 22" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 5.8125 7.535156 C 2.625 9.417969 0.015625 10.972656 0.0078125 10.992188 C -0.00390625 11.03125 11.585938 17.894531 11.65625 17.894531 C 11.6875 17.894531 11.699219 16.984375 11.703125 14.867188 L 11.714844 11.84375 L 16.808594 14.855469 C 19.609375 16.507812 21.921875 17.871094 21.949219 17.882812 C 21.992188 17.898438 22 16.804688 22 11 C 22 5.195312 21.992188 4.101562 21.949219 4.117188 C 21.921875 4.128906 19.609375 5.492188 16.808594 7.144531 L 11.714844 10.15625 L 11.703125 7.132812 C 11.695312 4.75 11.6875 4.105469 11.648438 4.105469 C 11.628906 4.109375 8.996094 5.648438 5.8125 7.535156 Z M 5.8125 7.535156 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 924 B

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="22pt" height="22pt" viewBox="0 0 22 22" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0.392157%,0%,0.784314%);fill-opacity:1;" d="M 10.332031 11.789062 L 10.332031 17.894531 L 22 11 L 10.332031 4.105469 L 10.332031 10.210938 L 0 4.105469 L 0 17.894531 Z M 10.332031 11.789062 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 461 B

@ -1843,6 +1843,29 @@
<signal name="activate" handler="ACTION_AUDIO_STOP_PLAYBACK" swapped="no"/>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menuAudioSeekForwards">
<property name="name">menuAudioSeekForwards</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Forward</property>
<property name="use_underline">True</property>
<signal name="activate" handler="ACTION_AUDIO_SEEK_FORWARDS" swapped="no"/>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menuAudioSeekBackwards">
<property name="name">menuAudioSeekBackwards</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Back</property>
<property name="use_underline">True</property>
<signal name="activate" handler="ACTION_AUDIO_SEEK_BACKWARDS" swapped="no"/>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menuEditTex">
<property name="name">menuEditTex</property>

@ -25,6 +25,13 @@
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkAdjustment" id="adjustmentSeekTime">
<property name="lower">1</property>
<property name="upper">90</property>
<property name="value">5</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustmentSnapGridTolerance">
<property name="lower">0.20000000000000001</property>
<property name="upper">10</property>
@ -3923,6 +3930,71 @@ If available select &lt;small&gt;&lt;tt&gt;pulse&lt;/tt&gt;&lt;/small&gt; as inp
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="sid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0.0099999997764825821</property>
<child>
<object class="GtkAlignment" id="sid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">8</property>
<property name="left_padding">12</property>
<property name="right_padding">12</property>
<child>
<object class="GtkGrid" id="sid3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">10</property>
<property name="column_spacing">10</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Default Seek Time (in seconds)</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spDefaultSeekTime">
<property name="name">spAudioGain</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">1,00</property>
<property name="adjustment">adjustmentSeekTime</property>
<property name="climb_rate">0.10000000000000001</property>
<property name="digits">2</property>
<property name="numeric">True</property>
<property name="value">1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="sid4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Playback Settings</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="sid182">
<property name="visible">True</property>
@ -3936,7 +4008,7 @@ If available select &lt;small&gt;&lt;tt&gt;pulse&lt;/tt&gt;&lt;/small&gt; as inp
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
</object>

@ -36,7 +36,7 @@ name = Portrait
name[de] = Hochformat
name[it] = Ritratto
name[ru] = Портретная
toolbarTop1 = SAVE,NEW,OPEN,SEPARATOR, CUT,COPY,PASTE,SEPARATOR, UNDO,REDO,SEPARATOR, GOTO_FIRST,GOTO_BACK,GOTO_NEXT_ANNOTATED_PAGE,GOTO_NEXT,GOTO_LAST,INSERT_NEW_PAGE,DELETE_CURRENT_PAGE,SEPARATOR ,FULLSCREEN,SEPARATOR, AUDIO_RECORDING,AUDIO_PAUSE_PLAYBACK,AUDIO_STOP_PLAYBACK,SEPARATOR, SELECT_FONT
toolbarTop1 = SAVE,NEW,OPEN,SEPARATOR, CUT,COPY,PASTE,SEPARATOR, UNDO,REDO,SEPARATOR, GOTO_FIRST,GOTO_BACK,GOTO_NEXT_ANNOTATED_PAGE,GOTO_NEXT,GOTO_LAST,INSERT_NEW_PAGE,DELETE_CURRENT_PAGE,SEPARATOR ,FULLSCREEN,SEPARATOR, AUDIO_RECORDING,AUDIO_SEEK_BACKWARDS,AUDIO_PAUSE_PLAYBACK,AUDIO_STOP_PLAYBACK,AUDIO_SEEK_FORWARDS,SEPARATOR, SELECT_FONT
toolbarTop2 = PEN,ERASER,HILIGHTER,IMAGE,TEXT,MATH_TEX,DRAW,SEPARATOR, ROTATION_SNAPPING,GRID_SNAPPING,SEPARATOR, SELECT,VERTICAL_SPACE,HAND,SEPARATOR, DEFAULT_TOOL,SEPARATOR, FINE,MEDIUM,THICK,SEPARATOR,TOOL_FILL,SEPARATOR,COLOR(0x000000),COLOR(0x008000),COLOR(0x00c0ff),COLOR(0x00ff00),COLOR(0x3333cc),COLOR(0x808080),COLOR(0xff0000),COLOR(0xff00ff),COLOR(0xff8000),COLOR(0xffff00),COLOR(0xffffff),COLOR_SELECT
toolbarBottom1 = PAGE_SPIN,SEPARATOR,LAYER, SPACER, PAIRED_PAGES,PRESENTATION_MODE,ZOOM_100,ZOOM_FIT,ZOOM_OUT,ZOOM_SLIDER,ZOOM_IN
@ -49,7 +49,7 @@ toolbarTop1 = SAVE,NEW,OPEN,SEPARATOR, CUT,COPY,PASTE,SEPARATOR, UNDO,REDO,SEPAR
toolbarBottom1 = PAGE_SPIN,SEPARATOR,LAYER,GOTO_FIRST,GOTO_NEXT_ANNOTATED_PAGE,GOTO_LAST,INSERT_NEW_PAGE,DELETE_CURRENT_PAGE,SPACER, PAIRED_PAGES,PRESENTATION_MODE,ZOOM_100,ZOOM_FIT,ZOOM_OUT,ZOOM_SLIDER,ZOOM_IN,SEPARATOR, FULLSCREEN
[Right hand Note Taking]
toolbarTop1=SAVE,NEW,OPEN,SEPARATOR,CUT,COPY,PASTE,SEPARATOR,UNDO,REDO,SEPARATOR,PEN,ERASER,HILIGHTER,IMAGE,TEXT,MATH_TEX,SEPARATOR,DEFAULT_TOOL,SEPARATOR,INSERT_NEW_PAGE,DELETE_CURRENT_PAGE,SEPARATOR,GOTO_BACK,GOTO_NEXT,SEPARATOR,FULLSCREEN,SEPARATOR,AUDIO_RECORDING,AUDIO_PAUSE_PLAYBACK,AUDIO_STOP_PLAYBACK
toolbarTop1=SAVE,NEW,OPEN,SEPARATOR,CUT,COPY,PASTE,SEPARATOR,UNDO,REDO,SEPARATOR,PEN,ERASER,HILIGHTER,IMAGE,TEXT,MATH_TEX,SEPARATOR,DEFAULT_TOOL,SEPARATOR,INSERT_NEW_PAGE,DELETE_CURRENT_PAGE,SEPARATOR,GOTO_BACK,GOTO_NEXT,SEPARATOR,FULLSCREEN,SEPARATOR,AUDIO_RECORDING,AUDIO_SEEK_BACKWARDS,AUDIO_PAUSE_PLAYBACK,AUDIO_STOP_PLAYBACK,AUDIO_SEEK_FORWARDS
toolbarLeft1=COLOR(0xffffff),COLOR(0xffff00),COLOR(0xff8000),COLOR(0xff00ff),COLOR(0x00ff00),COLOR(0x00c0ff),COLOR(0x808080),COLOR(0x008000),COLOR(0xff0000),COLOR(0x3333cc),COLOR(0x000000),COLOR_SELECT,SEPARATOR,PRESENTATION_MODE,ZOOM_100,ZOOM_FIT,ZOOM_IN,ZOOM_OUT
toolbarLeft2=FINE,MEDIUM,THICK,SEPARATOR,TOOL_FILL,SEPARATOR,DRAW_CIRCLE,DRAW_RECTANGLE,DRAW_ARROW,RULER,SEPARATOR,ROTATION_SNAPPING,GRID_SNAPPING,SEPARATOR,VERTICAL_SPACE,SELECT_REGION,SELECT_RECTANGLE,SELECT_OBJECT,PLAY_OBJECT
name=Right hand Note Taking

Loading…
Cancel
Save