diff --git a/src/control/AudioController.cpp b/src/control/AudioController.cpp index 985cc110..0ef5a8a1 100644 --- a/src/control/AudioController.cpp +++ b/src/control/AudioController.cpp @@ -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); diff --git a/src/control/AudioController.h b/src/control/AudioController.h index c0bdc09b..f49e000e 100644 --- a/src/control/AudioController.h +++ b/src/control/AudioController.h @@ -35,6 +35,8 @@ public: void pausePlayback(); void continuePlayback(); void stopPlayback(); + void seekForwards(); + void seekBackwards(); string getAudioFilename(); Path getAudioFolder(); diff --git a/src/control/Control.cpp b/src/control/Control.cpp index 8f4b9c1d..5bb01e2c 100644 --- a/src/control/Control.cpp +++ b/src/control/Control.cpp @@ -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; diff --git a/src/control/settings/Settings.cpp b/src/control/settings/Settings.cpp index f491ed31..a78ecbd0 100644 --- a/src/control/settings/Settings.cpp +++ b/src/control/settings/Settings.cpp @@ -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; diff --git a/src/control/settings/Settings.h b/src/control/settings/Settings.h index 82c4876a..b4d7faae 100644 --- a/src/control/settings/Settings.h +++ b/src/control/settings/Settings.h @@ -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) */ diff --git a/src/enums/ActionType.enum.h b/src/enums/ActionType.enum.h index 27e3f96a..42121945 100644 --- a/src/enums/ActionType.enum.h +++ b/src/enums/ActionType.enum.h @@ -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, diff --git a/src/enums/generated/ActionType.generated.cpp b/src/enums/generated/ActionType.generated.cpp index 84437845..207da948 100644 --- a/src/enums/generated/ActionType.generated.cpp +++ b/src/enums/generated/ActionType.generated.cpp @@ -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"; diff --git a/src/gui/dialog/SettingsDialog.cpp b/src/gui/dialog/SettingsDialog.cpp index dcba1c56..0c013220 100644 --- a/src/gui/dialog/SettingsDialog.cpp +++ b/src/gui/dialog/SettingsDialog.cpp @@ -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) { diff --git a/src/gui/toolbarMenubar/ToolMenuHandler.cpp b/src/gui/toolbarMenubar/ToolMenuHandler.cpp index 1bdc90c1..13883b7f 100644 --- a/src/gui/toolbarMenubar/ToolMenuHandler.cpp +++ b/src/gui/toolbarMenubar/ToolMenuHandler.cpp @@ -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) diff --git a/src/gui/toolbarMenubar/ToolMenuHandler.h b/src/gui/toolbarMenubar/ToolMenuHandler.h index 6e3a78f9..2872346a 100644 --- a/src/gui/toolbarMenubar/ToolMenuHandler.h +++ b/src/gui/toolbarMenubar/ToolMenuHandler.h @@ -97,6 +97,8 @@ private: ToolButton* audioPausePlaybackButton = nullptr; ToolButton* audioStopPlaybackButton = nullptr; + ToolButton* audioSeekBackwardsButton = nullptr; + ToolButton* audioSeekForwardsButton = nullptr; ToolPageSpinner* toolPageSpinner = nullptr; ToolPageLayer* toolPageLayer = nullptr; diff --git a/src/util/audio/AudioPlayer.cpp b/src/util/audio/AudioPlayer.cpp index 8306f4db..c4395ea5 100644 --- a/src/util/audio/AudioPlayer.cpp +++ b/src/util/audio/AudioPlayer.cpp @@ -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 AudioPlayer::getOutputDevices() { std::list deviceList = this->portAudioConsumer->getOutputDevices(); diff --git a/src/util/audio/AudioPlayer.h b/src/util/audio/AudioPlayer.h index 44f3a740..55324b74 100644 --- a/src/util/audio/AudioPlayer.h +++ b/src/util/audio/AudioPlayer.h @@ -30,6 +30,7 @@ public: void stop(); bool play(); void pause(); + void seek(int seconds); vector getOutputDevices(); diff --git a/src/util/audio/VorbisProducer.cpp b/src/util/audio/VorbisProducer.cpp index 2fc26b15..1224cfb2 100644 --- a/src/util/audio/VorbisProducer.cpp +++ b/src/util/audio/VorbisProducer.cpp @@ -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 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(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; +} \ No newline at end of file diff --git a/src/util/audio/VorbisProducer.h b/src/util/audio/VorbisProducer.h index d2a02353..6adc92af 100644 --- a/src/util/audio/VorbisProducer.h +++ b/src/util/audio/VorbisProducer.h @@ -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* audioQueue = nullptr; std::thread* producerThread = nullptr; + + int seekSeconds = 0; }; diff --git a/ui/icons/hicolor/icon-theme.cache b/ui/icons/hicolor/icon-theme.cache index 44f53564..69204ab3 100644 Binary files a/ui/icons/hicolor/icon-theme.cache and b/ui/icons/hicolor/icon-theme.cache differ diff --git a/ui/icons/hicolor/scalable/actions/audio-seek-backwards.svg b/ui/icons/hicolor/scalable/actions/audio-seek-backwards.svg new file mode 100644 index 00000000..10c278c5 --- /dev/null +++ b/ui/icons/hicolor/scalable/actions/audio-seek-backwards.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/ui/icons/hicolor/scalable/actions/audio-seek-forwards.svg b/ui/icons/hicolor/scalable/actions/audio-seek-forwards.svg new file mode 100644 index 00000000..b1f96893 --- /dev/null +++ b/ui/icons/hicolor/scalable/actions/audio-seek-forwards.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/ui/main.glade b/ui/main.glade index eab9d167..1da66af2 100644 --- a/ui/main.glade +++ b/ui/main.glade @@ -1843,6 +1843,29 @@ + + + + menuAudioSeekForwards + True + False + Forward + True + + + + + + + menuAudioSeekBackwards + True + False + Back + True + + + + menuEditTex diff --git a/ui/settings.glade b/ui/settings.glade index 752a8a85..7b1e7c53 100644 --- a/ui/settings.glade +++ b/ui/settings.glade @@ -25,6 +25,13 @@ 1 1 + + 1 + 90 + 5 + 1 + 10 + 0.20000000000000001 10 @@ -3923,6 +3930,71 @@ If available select <small><tt>pulse</tt></small> as inp 2 + + + True + False + 0.0099999997764825821 + + + True + False + 8 + 12 + 12 + + + True + False + 10 + 10 + + + True + False + Default Seek Time (in seconds) + 0 + + + 0 + 0 + + + + + spAudioGain + True + True + 1,00 + adjustmentSeekTime + 0.10000000000000001 + 2 + True + 1 + + + 1 + 0 + + + + + + + + + True + False + Playback Settings + + + + + False + True + 3 + + True @@ -3936,7 +4008,7 @@ If available select <small><tt>pulse</tt></small> as inp False True - 3 + 4 diff --git a/ui/toolbar.ini b/ui/toolbar.ini index e58dfef5..e78bea11 100755 --- a/ui/toolbar.ini +++ b/ui/toolbar.ini @@ -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