├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── ChangeLog ├── INSTALL ├── LICENSE ├── NEWS ├── NEWS-RU ├── README ├── TODO ├── afx.cpp ├── afx.h ├── cvlevelmeter.cpp ├── cvlevelmeter.h ├── db.cpp ├── db.h ├── desktop └── eko.desktop ├── docs └── index.html ├── document.cpp ├── document.h ├── eko.cpp ├── eko.h ├── eko.pro ├── eko.qrc ├── envelope.cpp ├── envelope.h ├── floatbuffer.cpp ├── floatbuffer.h ├── fman.cpp ├── fman.h ├── fx-filter.cpp ├── fx-filter.h ├── fx-panners.cpp ├── fx-panners.h ├── fxlist.cpp ├── fxlist.h ├── fxpresets.cpp ├── fxpresets.h ├── fxrack.cpp ├── fxrack.h ├── fxset.cpp ├── fxset.h ├── gui_utils.cpp ├── gui_utils.h ├── icons ├── create-dir.png ├── current-list.png ├── edit-copy-active.png ├── edit-copy.png ├── edit-cut-active.png ├── edit-cut.png ├── edit-paste-active.png ├── edit-paste.png ├── eko.png ├── file-new.png ├── file-open-active.png ├── file-open.png ├── file-save-active.png ├── file-save-as.png ├── file-save.png ├── go.png ├── home.png ├── pause.png ├── play.png ├── refresh.png ├── search_find.png └── stop.png ├── libretta_interpolator.cpp ├── libretta_interpolator.h ├── logmemo.cpp ├── logmemo.h ├── main.cpp ├── manuals ├── en.html └── ru.html ├── meson.build ├── noisegen.cpp ├── noisegen.h ├── palettes ├── EKO ├── Grey ├── Spring ├── Vinyl └── Winter ├── shortcuts.cpp ├── shortcuts.h ├── themes ├── Cotton │ └── stylesheet.css ├── Plum │ └── stylesheet.css ├── Smaragd │ └── stylesheet.css ├── TEA │ └── stylesheet.css ├── Turbo │ └── stylesheet.css └── Vegan │ └── stylesheet.css ├── tio.cpp ├── tio.h ├── translations ├── cs.qm ├── cs.ts ├── ru.qm └── ru.ts ├── utils.cpp └── utils.h /AUTHORS: -------------------------------------------------------------------------------- 1 | Code and design: 2 | 3 | Peter 'Roxton' Semiletov 4 | 5 | Standalone DX headers for MinGW - https://github.com/lifthrasiir/w32api-directx-standalone 6 | 7 | Used libraries: 8 | 9 | libsndfile, libsamplerate (http://www.mega-nerd.com/libsndfile/, http://www.mega-nerd.com/SRC/) by Erik de Castro Lopo 10 | Portaudio - http://www.portaudio.com 11 | 12 | ## 13 | Translators: 14 | 15 | Czech UI translation: Pavel Fric 16 | Russian UI translation and documentation: Peter Semiletov 17 | 18 | ## 19 | Packages and ports: 20 | 21 | need to update 22 | 23 | 24 | ## 25 | Acknowledgements: 26 | 27 | Thanks to (an incomplete and unsorted list): 28 | 29 | Nastia 30 | Shifter (downshft) 31 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #cmake_minimum_required(VERSION 3.0) 2 | cmake_minimum_required(VERSION 3.21.1) 3 | 4 | set (QT_MIN_VERSION "5.4.0") 5 | 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | set(CMAKE_AUTOMOC ON) 8 | set(CMAKE_AUTOUIC ON) 9 | set(CMAKE_AUTORCC ON) 10 | 11 | enable_language(CXX) 12 | enable_language(C) 13 | 14 | find_package(Qt6 COMPONENTS Core Widgets) 15 | if (NOT Qt6_FOUND) 16 | find_package(Qt5 5.15 REQUIRED COMPONENTS Core Widgets) 17 | endif() 18 | 19 | 20 | if (Qt6_FOUND) 21 | message("+ Qt6 found") 22 | set(CMAKE_CXX_STANDARD 17) 23 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 24 | find_package(Qt6 COMPONENTS Core5Compat REQUIRED) 25 | endif() 26 | 27 | 28 | qt_standard_project_setup() 29 | 30 | 31 | set(PROJECT "eko") 32 | project ($PROJECT VERSION 7.1.0 LANGUAGES CXX C) 33 | add_definitions(-DVERSION_NUMBER="\\"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}\\"") 34 | 35 | 36 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 37 | add_definitions(-DQ_OS_LINUX) 38 | add_definitions(-DQ_OS_UNIX) 39 | endif() 40 | 41 | 42 | message("CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") 43 | 44 | 45 | qt_add_resources(QT_RESOURCES eko.qrc) 46 | 47 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${QtWidgets_EXECUTABLE_COMPILE_FLAGS}") 48 | 49 | file(GLOB eko_SRCS "*.c" "*.cpp") 50 | file(GLOB eko_HEADERS "*.h") 51 | 52 | add_executable(eko ${eko_SRCS} ${QT_RESOURCES}) 53 | 54 | 55 | find_package(PkgConfig) 56 | 57 | pkg_check_modules(sndfile REQUIRED sndfile) 58 | if(sndfile_FOUND) 59 | target_link_libraries(eko ${sndfile_LIBRARIES}) 60 | # target_link_libraries(eko lsndfile) 61 | include_directories(${sndfile_INCLUDE_DIRS}) 62 | message("+ sndfile") 63 | endif() 64 | 65 | 66 | pkg_check_modules(samplerate REQUIRED samplerate) 67 | if(samplerate_FOUND) 68 | target_link_libraries(eko ${samplerate_LIBRARIES}) 69 | include_directories(${samplerate_INCLUDE_DIRS}) 70 | message("+ samplerate") 71 | endif() 72 | 73 | 74 | pkg_check_modules(portaudio2 REQUIRED portaudio-2.0) 75 | if(portaudio2_FOUND) 76 | target_link_libraries(eko ${portaudio2_LIBRARIES}) 77 | include_directories(${portaudio2_INCLUDE_DIRS}) 78 | message("+ portaudio") 79 | endif() 80 | 81 | 82 | set(eko_ICONPNG64 83 | ./icons/eko.png 84 | ) 85 | 86 | 87 | set(tea_DESKTOP 88 | ./desktop/eko.desktop 89 | ) 90 | 91 | 92 | add_custom_target(dist 93 | COMMAND git archive --format=tar --prefix=${PROJECT}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}/ HEAD | gzip >${PROJECT}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.tar.gz 94 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 95 | ) 96 | 97 | 98 | 99 | if (EXISTS "/usr/include/linux/joystick.h") 100 | message("+JOYSTICK_SUPPORTED") 101 | add_definitions(-DJOYSTICK_SUPPORTED) 102 | endif() 103 | 104 | 105 | if (Qt6_FOUND) 106 | target_link_libraries(eko Qt::Core5Compat) 107 | endif() 108 | 109 | target_link_libraries(eko Qt::Widgets Qt::Core) 110 | 111 | 112 | install (TARGETS eko DESTINATION bin) 113 | install (FILES ${eko_ICONPNG64} DESTINATION share/icons/hicolor/64x64/apps) 114 | install (FILES ${eko_DESKTOP} DESTINATION share/applications) 115 | 116 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2022 01 24 2 | +CMake support fixed 3 | 4 | 2017 dec 5 | * fixes 6 | 7 | 2017 jul 8 | * fixes 9 | + proper desktop intergration 10 | 11 | 2017 feb 12 | * resampler speed-up 13 | 14 | 2016 Sept 15 | * UI improvements 16 | * updated RU and EN manuals 17 | 18 | 19 | 2016 April 20 | * math fixes 21 | + FX presets 22 | 23 | 2016 jan 19 24 | + Fx - Vynil 25 | - GPL v3, EKO source is the pure Public Domain 26 | + EKO needs C++ 11 27 | 28 | 2016 jan - 5.0.0 29 | 30 | * heavy code modification 31 | 32 | 2015 nov, dec 33 | 34 | lots of changes 35 | 36 | 2015 nov 37 | * envelope code fixes 38 | 39 | 2015 oct 40 | + initial win32 port 41 | * Normalize function rewritten 42 | + Tune - Sound devices - Monitor input 43 | * Functions - Amplification = renamed to Dynamics 44 | + Help - System check 45 | + sound dynamics envelope 46 | 47 | * envelope - Shift-Click sets env point to the center, Ctrl-Click to delete the point 48 | 49 | 2015/sept, oct 50 | + FXRack changed to Mixer 51 | * selection fixes 52 | + MP3 and video files loading via FFMPEG or Mplayer 53 | + Alt-cursor, Shift-cursor - move selection border left/right 54 | + MP3 export using LAME 55 | * undo engine improvement 56 | etc 57 | 58 | 2015/july 59 | * math fixes 60 | 61 | 2015 62 | Qt5/Portaudio port 63 | 64 | 65 | 2014/may 66 | + Qt5 full support 67 | * GUI fixes 68 | 69 | 2013/may 70 | 71 | * Qt5 compatibility 72 | + FX rack per file 73 | + Simple delay effect 74 | 75 | 2013/04/08 76 | * non-visible fixes 77 | 78 | 2013/march 79 | + File manager from TEA //sync 80 | * UI fixes 81 | 82 | 2012/07/14 83 | + Qt5 port 84 | * large files opening fixes 85 | * time rules fixes 86 | 87 | 2012/03/14 88 | * fix for Unicode file names 89 | * some other fixes 90 | 91 | 92 | 2011/01/12 93 | + Edit - Copy to new (default format) //copy the data to new file with DEFAULT format 94 | 95 | 2011/01/06 96 | * aiff support fixes 97 | + simple pitch shifter realtime effect 98 | * SimpleAmp tweaks 99 | 100 | 2011/01/03 - editor focus fixes 101 | 2010/09/02 - smooth scrolling works 102 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | See the README -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | EKO code is Public Domain 2 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | _____________________________________________________ 2 | ===== NEWS ABOUT EKO ==== 3 | 4 | EKO 7.1.0, March 2024 5 | _____________________________________________________ 6 | 7 | http://psemiletov.github.io/eko/ 8 | _____________________________________________________ 9 | 10 | Important fixes for Qt6! 11 | 12 | 13 | Stay tuned. 14 | 15 | Peter Semiletov -------------------------------------------------------------------------------- /NEWS-RU: -------------------------------------------------------------------------------- 1 | _____________________________________________________ 2 | ===== НОВОСТИ ПРО ЭКО ==== 3 | 4 | EKO 7.1.0, март 2024 5 | _____________________________________________________ 6 | 7 | http://psemiletov.github.io/eko/ 8 | _____________________________________________________ 9 | 10 | 11 | Важные исправления для Qt6 12 | 13 | 14 | С кирпичным пролетарским приветом, Петр Семилетов! tea@list.ru -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ===EKO============ 2 | EKO is a simple sound editor. 3 | ================== 4 | 5 | http://psemiletov.github.io/eko/ 6 | 7 | PayPal donate: peter.semiletov@gmail.com 8 | BTC donate: 1PCo2zznEGMFJey4qFKGQ8CoFK2nzNnJJf 9 | 10 | ===INSTALLATION=== 11 | 12 | You need devel packages of Qt 5 or Qt6, portaudio, libsndfile and libsamplerate. 13 | C++ 11 compatible version of GCC or Clang. 14 | 15 | To build EKO from source using cmake (Qt5/Qt6 build): 16 | 17 | mkdir b 18 | cd b 19 | cmake .. 20 | make 21 | make install 22 | 23 | To build EKO from source using qmake (Qt5 build): 24 | 25 | qmake 26 | make 27 | make install 28 | 29 | 30 | ===NOTE FOR PACKAGE MAINTAINERS=== 31 | 32 | EKO after the compilation is a single binary file (with embeded resources). Please prefer cmake over qmake to build EKO. 33 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | to do or to fix: 2 | 3 | LV2 4 | VST 5 | 6 | Proxy не работает с ffmpeg!!!! 7 | 8 | добавить масштабирование к определенному коэф., например 100:2, 100:50 и т.д. 9 | 10 | при выключении в микшере правого канала при воспроизведении - вылет 11 | 12 | копировать канал, затем вставить - ничего не происходит 13 | 14 | перемотка к началу выделения не работает, при воспроизведении в петле 15 | 16 | повисает после select all и попытки сдвинуть затем правую границы выделения 17 | 18 | 19 | 20 | после ins_entry в fxrack надо сделать плагину ресет параметров!!! иначе тишина при добавлении при 21 | воспроизведении 22 | 23 | написать об Invalid number of channels в документации и при запуске Эко 24 | 25 | проверить запись с микрофона на встроенной звуковухе, сработает ли стерео 26 | 27 | 28 | надо создавать DSP при каждом play, и инициализировать внутри reset_state 29 | 30 | после применения удаления и т.п. в волновой форме показывается мусор в конце 31 | 32 | 33 | если петля на весь файл, и есть выделение, то петлевание не пашет 34 | "вставить в новый С ФОРМАТОМ ПО УМОЛЧАНИЮ" не работает 35 | 36 | 37 | нельзя ли выкинуть transport_state? 38 | 39 | * сделать все крутилки и фэйдеры нелинейными 40 | 41 | * эко не открывает файлы из командной строки - исправить 42 | * игрища с OpenMP 43 | 44 | выделение подвисает 45 | 46 | * создавать в темпе отдельный подкаталог под эко 47 | * вернуть старый нормализатор под именем Normalize auto 48 | * так ли нужно создавать три точки автоматически? 49 | * CTinyPlayer - disk-based player for the audio preview at FM page 50 | * добавить возникновение выделение по курсор-шифт, курсор-алт 51 | * при петле, автоскроллинг не пашет туда-сюда 52 | * починить шкалу dB слева от волновой формы (два нуля, два столбика) 53 | * caching subsystem 54 | * zoom to selection 55 | 56 | * fix search via FIF 57 | * fix profiles engine //? 58 | * level meter < -26 dB 59 | * inspect fn_detect_average_value 60 | * noise gate realtime effect 61 | * dc offset functions - check stereo support 62 | * add space when FXRack apply needs more file length //test with pitch shifter 63 | * 10-th seconds timeruler markers when > 1 min 64 | * fix Import RAW 65 | * implement Export RAW 66 | * add data modification status 67 | * rewrite fx internal data to save/load presets 68 | * FX rack presets 69 | * FX presets 70 | * reorder fx via drag'n'drop 71 | * looped play is not loop-range accurate? 72 | * level meter with precise time-based peaks falloff 73 | * paste with (mix) 74 | * redo 75 | * UI for RAW files 76 | * add warning on flush_undo() 77 | * mixer for channels > 2 78 | * time ruler redraw and palette 79 | * markers per file 80 | * noise, fm synthesis for testing purposes 81 | * big/little endian at file format window? 82 | * stop playback on offline effect 83 | 84 | * disk cache? save temp float file - mmap - memcpy the window? 85 | -------------------------------------------------------------------------------- /afx.cpp: -------------------------------------------------------------------------------- 1 | #include "afx.h" 2 | 3 | 4 | AFx::AFx() 5 | { 6 | bypass = false; 7 | realtime = true; 8 | ui_visible = false; 9 | float_buffer = 0; 10 | 11 | state = FXS_STOP; 12 | classname = "AFx"; 13 | modulename = "AFx"; 14 | 15 | samplerate = 1; 16 | channels = 1;//chann; 17 | 18 | wnd_ui = new QWidget(); 19 | 20 | vbl_main = new QVBoxLayout; 21 | wnd_ui->setLayout (vbl_main); 22 | 23 | presets = new CFxPresets; 24 | 25 | connect (presets, SIGNAL(save_request()), this, SLOT(slot_save_request())); 26 | connect (presets, SIGNAL(preset_changed(QString)), this, SLOT(slot_preset_changed(QString))); 27 | 28 | w_caption = new QWidget; 29 | QVBoxLayout *vbl_caption = new QVBoxLayout; 30 | w_caption->setLayout (vbl_caption); 31 | 32 | vbl_main->addWidget (presets); 33 | vbl_main->addWidget (w_caption); 34 | 35 | l_caption = new QLabel; 36 | l_subcaption = new QLabel; 37 | 38 | vbl_caption->addWidget (l_caption); 39 | vbl_caption->addWidget (l_subcaption); 40 | 41 | QString qstl = "QWidget#w_caption{" 42 | "border-radius: 15px;" 43 | "background-color: grey;}"; 44 | 45 | w_caption->setObjectName ("w_caption"); 46 | w_caption->setStyleSheet (qstl); 47 | } 48 | 49 | 50 | void AFx::set_caption (const QString &capt, const QString &subcapt) 51 | { 52 | l_caption->setText (capt); 53 | l_subcaption->setText (subcapt); 54 | } 55 | 56 | 57 | AFx::~AFx() 58 | { 59 | if (wnd_ui) 60 | { 61 | wnd_ui->close(); 62 | delete wnd_ui; 63 | } 64 | } 65 | 66 | 67 | void AFx::show_ui() 68 | { 69 | if (wnd_ui) 70 | wnd_ui->setVisible (! wnd_ui->isVisible()); 71 | } 72 | 73 | 74 | void AFx::set_state (FxState s) 75 | { 76 | state = s; 77 | } 78 | 79 | 80 | void AFx::reset_params (size_t srate, size_t chann) 81 | { 82 | samplerate = srate; 83 | channels = chann; 84 | } 85 | 86 | 87 | void AFx::slot_preset_changed (const QString &text) 88 | { 89 | load_params_from_string (text); 90 | } 91 | 92 | 93 | void AFx::slot_save_request() 94 | { 95 | presets->preset_data = save_params_to_string(); 96 | } 97 | -------------------------------------------------------------------------------- /afx.h: -------------------------------------------------------------------------------- 1 | #ifndef AFX_H 2 | #define AFX_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #include "floatbuffer.h" 16 | #include "fxpresets.h" 17 | 18 | 19 | enum FxState { 20 | FXS_STOP, 21 | FXS_RUN, 22 | FXS_PAUSE 23 | }; 24 | 25 | 26 | class AFx: public QObject 27 | { 28 | Q_OBJECT 29 | 30 | public: 31 | 32 | FxState state; 33 | 34 | bool bypass; 35 | bool realtime; 36 | bool ui_visible; 37 | 38 | CFloatBuffer *float_buffer; //inner buffer for some purposes 39 | 40 | size_t channels; 41 | size_t samplerate; 42 | 43 | CFxPresets *presets; 44 | 45 | QWidget *wnd_ui; 46 | QVBoxLayout *vbl_main; 47 | 48 | QWidget *w_caption; 49 | QLabel *l_caption; 50 | QLabel *l_subcaption; 51 | 52 | QString classname; 53 | QString modulename; 54 | 55 | AFx(); 56 | 57 | ~AFx(); 58 | 59 | virtual size_t execute (float **input, float **output, size_t frames) = 0; 60 | 61 | //virtual void state_save_xml (QXmlStreamWriter *writer) = 0; 62 | 63 | virtual QString save_params_to_string() = 0; 64 | virtual void load_params_from_string (const QString &s) = 0; 65 | 66 | virtual void set_state (FxState s); 67 | virtual void reset_params (size_t srate, size_t ch); 68 | 69 | void set_caption (const QString &capt, const QString &subcapt); 70 | 71 | void show_ui(); 72 | 73 | virtual AFx* self_create() = 0; 74 | 75 | static QString get_modulename() {return QString ("AFx");}; 76 | 77 | public slots: 78 | 79 | void slot_preset_changed (const QString &text); 80 | void slot_save_request(); 81 | 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /cvlevelmeter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "cvlevelmeter.h" 5 | #include "utils.h" 6 | #include "db.h" 7 | 8 | 9 | void CVLevelMeter::update_scale_image() 10 | { 11 | QImage im (scale_width, height(), QImage::Format_RGB32); 12 | 13 | QPainter painter (&im); 14 | 15 | painter.fillRect (0, 0, scale_width, height(), Qt::white); 16 | 17 | painter.setPen (Qt::black); 18 | painter.setFont (QFont ("Mono", 6)); 19 | 20 | int ten = get_value (height(), 5); 21 | 22 | int percentage = 105; 23 | float ff = 0.0f; 24 | 25 | for (int y = 0; y < height(); y++) 26 | { 27 | if (! (y % ten)) 28 | { 29 | percentage -= 5; 30 | 31 | ff = (1.0 / 100) * percentage; 32 | 33 | QPoint p1 (1, y); 34 | QPoint p2 (scale_width, y); 35 | painter.drawLine (p1, p2); 36 | 37 | painter.drawText (QPoint (1, y), QString::number (float2db (ff), 'g', 2)); //dB 38 | } 39 | } 40 | 41 | img_bar = im; 42 | } 43 | 44 | 45 | void CVLevelMeter::resizeEvent(QResizeEvent *event) 46 | { 47 | update_scale_image(); 48 | } 49 | 50 | 51 | CVLevelMeter::CVLevelMeter (QWidget *parent) 52 | { 53 | peak_l = 0; 54 | peak_r = 0; 55 | 56 | scale_width = 42; 57 | bars_width = 48; 58 | 59 | setMinimumWidth (scale_width + bars_width); 60 | 61 | resize (scale_width + bars_width, 256); 62 | } 63 | 64 | 65 | #define FALLOFF_COEF 0.05f 66 | 67 | void CVLevelMeter::paintEvent (QPaintEvent *event) 68 | { 69 | if (pl > peak_l) 70 | peak_l = pl; 71 | else 72 | peak_l -= FALLOFF_COEF; 73 | 74 | if (pr > peak_r) 75 | peak_r = pr; 76 | else 77 | peak_r -= FALLOFF_COEF; 78 | 79 | if (peak_l < -1 || peak_l > 1) 80 | peak_l = 0; 81 | 82 | if (peak_r < -1 || peak_r > 1) 83 | peak_r = 0; 84 | 85 | QPainter painter (this); 86 | 87 | int h = height(); 88 | int w = width(); 89 | 90 | painter.fillRect (scale_width, 0, w, h, Qt::white); 91 | 92 | int lenl = h - (int)(peak_l * 1.0f * h); 93 | int lenr = h - (int)(peak_r * 1.0f * h); 94 | 95 | QPoint ltop (scale_width, h); 96 | QPoint lbottom (scale_width + (w - scale_width) / 2, lenl); 97 | 98 | QPoint rtop (scale_width + (w - scale_width) / 2, h); 99 | QPoint rbottom (w, lenr); 100 | 101 | QRect l (ltop, lbottom); 102 | QRect r (rtop, rbottom); 103 | 104 | painter.fillRect (l, Qt::green); 105 | painter.fillRect (r, Qt::darkGreen); 106 | 107 | painter.drawImage (1, 1, img_bar); 108 | 109 | event->accept(); 110 | } 111 | -------------------------------------------------------------------------------- /cvlevelmeter.h: -------------------------------------------------------------------------------- 1 | #ifndef CVLEVELMETER_H 2 | #define CVLEVELMETER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class CVLevelMeter: public QWidget 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | 15 | bool init_state; 16 | 17 | QImage img_bar; 18 | 19 | int scale_width; 20 | int bars_width; 21 | 22 | float peak_l; 23 | float peak_r; 24 | float pl; 25 | float pr; 26 | 27 | CVLevelMeter (QWidget *parent); 28 | 29 | void update_scale_image(); 30 | 31 | protected: 32 | 33 | void paintEvent (QPaintEvent *event); 34 | void resizeEvent (QResizeEvent *event); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /db.cpp: -------------------------------------------------------------------------------- 1 | #include "db.h" 2 | 3 | double db_scale; 4 | 5 | void init_db() 6 | { 7 | db_scale = log (10.0) * 0.05; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /db.h: -------------------------------------------------------------------------------- 1 | #ifndef DB_H 2 | #define DB_H 3 | 4 | #include 5 | 6 | extern double db_scale; 7 | 8 | inline float db2lin (float db) 9 | { 10 | return (float) exp (db * db_scale); 11 | } 12 | 13 | /* 14 | static inline float db2lin (float db) 15 | { 16 | return powf (10.0f, db / 20); 17 | } 18 | */ 19 | 20 | 21 | inline float float2db (float v) 22 | { 23 | if (v == 0.0f) 24 | return 0.0f; 25 | 26 | if (v > 0.0f) 27 | return (float) 20 * log10 (v / 1.0); 28 | 29 | return (float) 20 * log10 (v / -1.0); 30 | } 31 | 32 | 33 | void init_db(); 34 | 35 | #endif // DB_H 36 | -------------------------------------------------------------------------------- /desktop/eko.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=EKO 3 | Terminal=false 4 | Type=Application 5 | Icon=eko 6 | Categories=AudioVideo;Audio; 7 | StartupNotify=false 8 | NoDisplay=false 9 | Keywords=sound editor;sound;editor; 10 | Comment=Simple audio editor with mixer and realtime effects 11 | Comment[ru]=Редактор звука с микшером и эффектами 12 | Comment[fr]=Éditeur audio simple avec un mixeur et des effets temps-réel 13 | Exec=eko %U 14 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | EKO 8 | 9 | 10 | 11 | 12 | 13 | 14 |

EKO: звуковой редактор / audio editor

15 | 16 |
17 | 18 |

О программе/About - Скачать/Download - 19 | Github - 20 | Поддержать/Donate


21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 99 | 100 | 165 | 166 | 167 |
29 |

Новости:

30 | 31 | 32 |

8 марта 2024 - выпущена 33 | версия 7.1.0. Важные исправления для Qt6.

34 | 35 |

20 января 2022 - выпущена 36 | версия 7.0.0. Эко портирован на Qt6.

37 | 38 | 39 |

23 мая 2019 - выпущена 40 | версия 6.0.0. После двухлетнего перерыва - шестая версия, призванная стать надежной основой для дальнейшего развития программы. Исправлена подсистема ввода-вывода, добавлено меню Масштаб, много чего еще исправлено. 41 |

42 | 43 | 44 |

8 марта 2017 - выпущена 45 | версия 5.3.3. Добавлена настройка ресэмплера на страницу Наладки - Общие. Вместо режима "только чтение" для форматов, сохранять в которые Эко не умеет, теперь при попытке сохранить - сохраняется в ВАВ. Для скачивания доступны исходник, AppImage и сборка для Windows. 46 |

47 | 48 | 49 |

5 марта 2017 - выпущена 50 | версия 5.3.2. Исправлено сохранение в выбранном формате, ускорен ресэмплер. Для скачивания доступны исходник, AppImage и сборка для Windows. 51 |

52 | 53 |

27 февраля 2017 - выложен AppImage EKO, версия из гитхаба. Вот откуда скачать.

54 | 55 | 56 |

20 января 2017 - выложен EKO 5.3.1. Вот исходник, который снова стал компилироваться под Qt4.

57 | 58 |

27 сентября 2016 - выложен EKO 5.3.0. Вот исходник, а вот сборка под Windows. В этой версии подправлен интерфейс Настроек, чтобы лучше выглядеть при низких разрешениях экрана. Небольшие изменения в названиях вкладок справа.

59 | 60 | 61 |

22 июня 2016 - выложен EKO 5.2.0. Вот исходник, а вот сборка под Windows. В этой версии - исправления ошибок, связанных с обработкой отдельных каналов. Также добавлены некоторые красивости, например волновая форма пустого нового файла теперь выглядит как перечеркнутый прямоугольник.

62 | 63 |

13 апреля 2016 - выложен EKO 5.1.0. Вот исходник, а вот сборка под Windows. В этой версии - механизм пресетов для эффектов, а также новый эффект - Вкус винила - эмулирующий шум и царапины виниловой пластинки.

64 | 65 |

15 января 2016 - выпущен EKO 5.0.0. Вот исходник, а вот сборка под Windows.

66 | 67 |

Пятая версия. Я снова переписал программу почти с нуля, но пользователям это не должно быть заметно. Изменения больше внутренние, потому что часть исходного кода Эко используется теперь в исходнике моего нового проекта, минималистической DAW Wavylon (Вавилон).

68 |

А что же нового для пользователя? Более надёжная работа всей программы. Несколько новых эффектов реального времени - фильтр, задержка, и две гитарные примочки (Жесть и Металюга), которые разработаны более для Вавилона, нежели для Эко. 69 |

Основные изменения в Эко произошли внутри и позволят мне развивать редактор дальше. 70 |

71 | 72 |

6 ноября 2015 - выпущен EKO 4.0.0. Вот исходник, а вот сборка под Windows.

73 | 74 |

Ой-ой-ой! Он снова выложил новую "большую" версию! Что же?

75 |

В ней я исправил ошибок больше, чем звезд на небе. Так стыдно за них! В коде выделения областей, обработки каналов более двух, да много было. 76 |

Функция нормализации звука теперь принимает параметр, можно задать децибелы. При записи звука, доступна опция мониторинга, это чтобы слышать то, что поступает на вход. 77 |

Почти как во солидных программах, появилась огибающая, правда пока только одна, для управления громкостью. Ну и меню "Функции - Динамика" к этому прилагается. Подробности читайте в документации, тут лень писать. 78 |

Наконец, самый стрёмный для меня момент - с выпуском четвертой версии я выкладываю первую сборку под Windows. Я ее почти не тестировал, так что того. 79 |

80 | 81 |

12 октября 2015 - выпущен EKO 3.0.0.

82 | 83 |

Эта версия подарит вам много новых ошибок. Однако другие новшества стоят того.

84 |

Эко научился читать MP3 и видеофайлы посредством внешних утилит, FFMPEG и Mplayer (на ваше усмотрение). Экспорт в MP3 при помощи LAME. Стойка эффектов превратилась в Микшер (я едва удержался от соблазна назвать его Сводником) с громкостью и панорамой. 85 |

Много чего переписано и сильно улучшено - код выделения области, механизм отмен, и прочее. 86 | Всему этому нужно утрястись, исправиться в следующих версиях. 87 |

88 | 89 | 90 |

21 июля 2015 - выпущен EKO 2.1.0, с разными исправлениями. 91 |

92 | 93 | 94 |

27 апреля 2015 - вышел EKO 2.0.0. Спустя почти год молчания - новая версия, да еще какая! Поддержка JACK убрана, вместо этого Эко использует для звукового ввода-вывода библиотеку Portaudio, как Audacity. Внутренний звуковой движок переписан, добавлена возможность записи, поддержка тем оформления. 95 | Исправлены многочисленные старые ошибки и добавлены новые. 96 |

97 | 98 |
101 |

News:

102 | 103 | 104 |

March 08 2024 - version 7.1.0 Fixes for Qt6!

105 | 106 | 107 |

Jan 20 2022 - version 7.0.0 Meet the Qt6 port!

108 | 109 | 110 |

May 32 2019 - version 6.0.0 is out. This version is a basis for further improvements. IO subsystem has been fixed. New Zoom menu, code cleanup.

111 | 112 | 113 | 114 |

March 8 2017 - version 5.3.3 is out as source, AppImage and Windows build. More fixes. Resampler options has been added to the settings "Common" page. No "read-only" mode now - when the saving to the original format is not supported, EKO will save to WAV.

115 | 116 | 117 |

March 5 2017 - version 5.3.2 is out as source, AppImage and Windows build. Some fixes of saving in the different format behavior, and the resampler is faster now.

118 | 119 | 120 | 121 |

January 20 2017 - EKO appimage is out. Here is AppImage.

122 | 123 | 124 |

January 20 2017 - EKO 5.3.1 is out. Here is the source with Qt4-compatibility fixes.

125 | 126 |

September 27 2016 - EKO 5.3.0 is out. Here is the source, and the Windows build. Some GUI improvements.

127 | 128 |

June 22 2016 - EKO 5.2.0 is out. Here is the source, and the Windows build. Channel handling fixes, some GUI improvements.

129 | 130 |

April 13 2016 - EKO 5.1.0 is out. Here is the source, and the Windows build. This release features FX presets engine, and the new effect Vynil Taste that simulates vynil plate noises.

131 | 132 | 133 |

January 15 2016 - EKO 5.0.0 is out. Here is the source, and the Windows build.

134 | 135 | 136 |

Hello! The fifth EKO's code has been heavy rewritten to share the codebase with my new project, the minimalistic DAW - Wavylon. Also there are many errors were fixed, and limitations eliminated. But what is changed for the user?

137 |

EKO becomes more stable. Some new realtime FX - two guitar pedals emulators, the filter and the delay module. But they are will be more useful with Wavylon. 138 |

So there is not so much visible and audible changes but the inner changes allows me to move EKO forward. 139 |

140 |

November 6 2015 - EKO 4.0.0 is out. Here is the source, and the Windows build.

141 | 142 |

First of all, this release fixes all bugs those I knew. It includes the multilply (more than 2) channels processing, fading, selections and many more.

143 |

The "Normalize" function now takes the parameter in dB. 144 |

Now you can monitor the input signal (Tune - Sound devices - Monitor input option). 145 |

The volume can be adjusted dynamically using the volume (or dynamics) automation envelope and "Functions - Dynamics" menu. 146 |

147 | With the 4.0.0 I'm afraid (yes) to introduce the initial Win32 build that I didn't test much. 148 |

149 |

October 12, 2015 - EKO 3.0.0 is out!

150 | 151 |

Many new bugs are presented to you with the new major release! 152 |

But new features are worth that. 153 |

Now EKO is able to open MP3 and videofiles (as audio) using external command line tools FFMPEG or Mplayer. MP3 export via LAME. FXRack has been modified to the Mixer. Undo engine has been improved. A lot of internals has been rewritten, including the selection and looping code. 154 |

155 | 156 |

July 21, 2015 - EKO 2.1.0 is out! Misc fixes.

157 | 158 | 159 |

April 27, 2015 - EKO 2.0.0 is out!

160 | 161 |

Major release. Too good to be described properly. JACK support has been dropped. Now EKO works with sound using Portaudio (as Audacity). Inner sound engine has been rewritten, adding the recording suppord and GUI themes. Bugfixes, new bugs introducing, etc. 162 |

163 | 164 |
168 | 169 | 170 | 171 | 172 | 173 | 202 | 203 | 234 | 235 | 236 |
174 |

О программе, глюки, возможности

175 | 176 |

О программе:

177 | 178 |

Эко - простой звуковой редактор для Linux и Windows.

179 | 180 |

Для его установки из исходника вам понадобятся Qt 4 или 5, portaudio, libsndfile, libsamplerate и компилятор GCC. Внешние, необязательные утилиты для поддержки MP3 и видеофайлов: FFMPEG или Mplayer, а также LAME.

181 | 182 |

EKO понимает все популярные форматы и удобен для правки/нарезки небольших файлов. Внешние эффекты пока не поддерживаются, а встроенных мало.

183 | 184 |

Возможности:

185 | 186 |
    187 | 188 |
  • эффекты реального времени
  • 189 |
  • генератор синусоиды и шума
  • 190 |
  • конвертор каналов
  • 191 |
  • анализ RMS и уровня
  • 192 |
  • сдвиг DC
  • 193 |
  • реверс
  • 194 |
  • удобная "нарезка"
  • 195 |
  • смена палитр
  • 196 |
  • настройка горячих клавиш
  • 197 | 198 |
199 | 200 | 201 |
204 |

About, Issues, Features

205 | 206 | 207 |

About:

208 | 209 | 210 |

EKO is a simple sound editor with the mixer.

211 | 212 | 213 |

To install EKO from the source, you need just a modern version of Qt 4 or 5, portaudio, libsndfile, libsamplerate and of course GCC or Clang. For MP3 and video decoding EKO uses external FFMPEG or Mplayer, and LAME for the MP3 encoding.

214 | 215 |

EKO understands all popular sound formats and useful in simple editing (cut/copy/paste) with a minimum FX processing. External fx currently are not supported.

216 | 217 | 218 |

Features:

219 | 220 |
    221 | 222 |
  • real-time FX rack
  • 223 |
  • generators of sine, noise
  • 224 |
  • channel converter
  • 225 |
  • RMS and level analysis
  • 226 |
  • DC offset corrector
  • 227 |
  • reverese
  • 228 |
  • handy editing
  • 229 |
  • color palettes
  • 230 |
  • hotkeys customizations
  • 231 | 232 |
233 |
237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 255 | 256 | 264 | 265 | 266 |
246 |

Скачать

247 | 248 | EKO 7.1.0 - исходник
249 | 250 | EKO 6.0.0 - сборка под Windows
251 | 252 | EKO на Гитхабе 253 | 254 |
257 |

Download

258 | 259 | EKO 7.1.0 - source code tarball
260 | EKO 6.0.0 - Windows build
261 | EKO on Github
262 | 263 |
267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 281 | 282 | 283 | 289 | 290 | 291 |
276 |

Поддержать

277 | 278 | PayPal: peter.semiletov@gmail.com
279 | BuyMeACoffee - https://www.buymeacoffee.com/semiletov 280 |
284 |

Donate

285 | 286 | PayPal: peter.semiletov@gmail.com
287 | BuyMeACoffee - https://www.buymeacoffee.com/semiletov 288 |
292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /document.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 2010-2021 by Peter Semiletov * 3 | * peter.semiletov@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 3 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * aint with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 | ***************************************************************************/ 20 | 21 | 22 | #ifndef DOCUMENT_H 23 | #define DOCUMENT_H 24 | 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | 40 | #include "logmemo.h" 41 | #include "tio.h" 42 | #include "floatbuffer.h" 43 | #include "envelope.h" 44 | #include "cvlevelmeter.h" 45 | #include "fxrack.h" 46 | 47 | 48 | 49 | enum ETransportStates 50 | { 51 | STATE_STOP = 0, 52 | STATE_PLAY, 53 | STATE_PAUSE, 54 | STATE_EXIT, 55 | STATE_RECORD 56 | }; 57 | 58 | 59 | enum EUndoModes 60 | { 61 | UNDO_UNDEFINED = 0, 62 | UNDO_DELETE, 63 | UNDO_PASTE, 64 | UNDO_MODIFY, 65 | UNDO_WHOLE, 66 | UNDO_INSERT 67 | }; 68 | 69 | 70 | class CDocumentHolder; 71 | class CDocument; 72 | 73 | 74 | class CTransportControl: public QObject 75 | { 76 | Q_OBJECT 77 | 78 | signals: 79 | 80 | void play_pause(); 81 | void stop(); 82 | 83 | public: 84 | 85 | void call_play_pause(); 86 | void call_stop(); 87 | }; 88 | 89 | 90 | class CUndoElement: public QObject 91 | { 92 | Q_OBJECT 93 | 94 | public: 95 | 96 | int type; 97 | bool selected; 98 | 99 | size_t frames_per_section; 100 | 101 | size_t start_frames; //selection start 102 | size_t end_frames; //selection end 103 | 104 | size_t cursor_frames; 105 | 106 | CFloatBuffer *fb; 107 | 108 | CUndoElement(); 109 | ~CUndoElement(); 110 | }; 111 | 112 | 113 | class CChannelSamples 114 | { 115 | public: 116 | 117 | float *samples; 118 | float temp; 119 | 120 | CChannelSamples (size_t size); 121 | ~CChannelSamples(); 122 | }; 123 | 124 | 125 | class CChannelMinmax 126 | { 127 | public: 128 | 129 | CChannelSamples *min_values; 130 | CChannelSamples *max_values; 131 | 132 | CChannelMinmax (size_t size); 133 | ~CChannelMinmax(); 134 | }; 135 | 136 | 137 | class CMinmaxes 138 | { 139 | public: 140 | 141 | CChannelMinmax **values; 142 | 143 | size_t count; 144 | 145 | CMinmaxes (size_t size, size_t sections); 146 | ~CMinmaxes(); 147 | }; 148 | 149 | 150 | class CWaveform; 151 | 152 | 153 | class CTimeRuler: public QWidget 154 | { 155 | Q_OBJECT 156 | 157 | public: 158 | 159 | CWaveform *waveform; 160 | bool init_state; 161 | 162 | QColor background_color; 163 | QColor foreground_color; 164 | 165 | CTimeRuler (QWidget *parent); 166 | 167 | protected: 168 | 169 | void paintEvent (QPaintEvent *event); 170 | }; 171 | 172 | 173 | class CWaveEdit; 174 | 175 | 176 | class CWaveform: public QWidget 177 | { 178 | Q_OBJECT 179 | 180 | public: 181 | 182 | //top-level link: 183 | CWaveEdit *wave_edit; 184 | 185 | CFloatBuffer *fb; 186 | CTimeRuler *timeruler; 187 | 188 | CEnvelope env_vol; 189 | 190 | bool show_db; //false if floats 191 | bool play_looped; 192 | 193 | int selection_selected; //0 - non, 1 - left, 2 - right 194 | int envelope_selected; //-1 - non 195 | 196 | CMinmaxes *minmaxes; 197 | QScrollBar *scrollbar; 198 | 199 | QTimer timer; 200 | 201 | bool init_state; 202 | bool draw_shadow; 203 | 204 | bool mouse_pressed; 205 | bool normal_cursor_shape; 206 | bool selected; 207 | 208 | QImage waveform_image; 209 | 210 | float scale_factor; 211 | 212 | int previous_mouse_pos_x; 213 | 214 | size_t sel_start_frames; 215 | size_t sel_end_frames; 216 | 217 | //calculates positions: 218 | 219 | int get_cursor_position_sections(); //in sections 220 | int get_selection_start_sections(); //in sections 221 | int get_selection_end_sections(); //in sections 222 | 223 | void set_cursor_by_section (size_t section); 224 | 225 | size_t frames_per_section; 226 | size_t sections_total; 227 | 228 | size_t get_section_from(); 229 | size_t get_section_to(); 230 | 231 | //colors 232 | 233 | QColor cl_waveform_background; 234 | QColor cl_waveform_foreground; 235 | QColor cl_waveform_selection_foreground; 236 | QColor cl_axis; 237 | QColor cl_cursor; 238 | QColor cl_text; 239 | QColor cl_envelope; 240 | QColor cl_env_point_selected; 241 | QColor cl_shadow; 242 | 243 | int waveform_selection_alpha; 244 | 245 | void load_color (const QString &fname); 246 | 247 | //end of colors 248 | 249 | 250 | CWaveform (QWidget *parent); 251 | ~CWaveform(); 252 | 253 | void set_cursor_value (size_t section); 254 | void set_selstart_value (size_t section); 255 | void set_selend_value (size_t section); 256 | 257 | void set_statusbar_text(); 258 | void set_cursorpos_text(); 259 | 260 | void scalef (float factor, size_t start_frm); 261 | 262 | void scale (int delta); 263 | void zoom (int factor); 264 | 265 | 266 | void recalc_view(); 267 | void prepare_image(); 268 | 269 | void magic_update(); 270 | void fix_selection_bounds(); 271 | 272 | void deselect(); 273 | void select_all(); 274 | 275 | void copy_selected(); 276 | void delete_selected(); 277 | void cut_selected(); 278 | 279 | void paste(); 280 | 281 | size_t frames_start(); 282 | size_t frames_end(); 283 | 284 | void set_cursor_to_frames (size_t frame); 285 | 286 | //undo/redo stuff 287 | QList undos; 288 | int max_undos; 289 | // int current_undo; 290 | 291 | void undo_take_shot (int type, int param = 0); 292 | void undo_top(); //simple test of the undo 293 | 294 | void flush_undos(); 295 | 296 | void redo(); 297 | 298 | 299 | protected: 300 | 301 | // void dragEnterEvent (QDragEnterEvent *event); 302 | // void dropEvent (QDropEvent *event); 303 | void paintEvent(QPaintEvent *event); 304 | void mousePressEvent (QMouseEvent *event); 305 | void wheelEvent (QWheelEvent *event ); 306 | void keyPressEvent (QKeyEvent *event); 307 | void resizeEvent(QResizeEvent *event); 308 | 309 | void mouseMoveEvent (QMouseEvent *event); 310 | void mouseReleaseEvent (QMouseEvent * event); 311 | 312 | void mouseDoubleClickEvent ( QMouseEvent * event); 313 | 314 | public slots: 315 | 316 | void timer_timeout(); 317 | 318 | }; 319 | 320 | 321 | class CWaveEdit: public QWidget 322 | { 323 | Q_OBJECT 324 | 325 | public: 326 | 327 | CDocument *doc; 328 | CWaveform *waveform; 329 | QScrollBar *scb_horizontal; 330 | CTimeRuler *timeruler; 331 | 332 | CWaveEdit (QWidget *parent = 0); 333 | ~CWaveEdit(); 334 | 335 | bool isReadOnly(); 336 | 337 | protected: 338 | 339 | void dragEnterEvent (QDragEnterEvent *event); 340 | void dropEvent (QDropEvent *event); 341 | 342 | public slots: 343 | 344 | void scb_horizontal_valueChanged (int value); 345 | 346 | }; 347 | 348 | 349 | class CDocument: public QObject 350 | { 351 | Q_OBJECT 352 | 353 | public: 354 | 355 | QHash fnameswoexts; 356 | 357 | CDocumentHolder *holder; 358 | 359 | CWaveEdit *wave_edit; 360 | 361 | QString file_name; 362 | QWidget *tab_page; 363 | 364 | size_t position; 365 | 366 | bool ronly; 367 | 368 | CDocument (QObject *parent = 0); 369 | ~CDocument(); 370 | 371 | 372 | int get_tab_idx(); 373 | void set_tab_caption (const QString &fileName); 374 | 375 | void create_new(); 376 | 377 | bool save_with_name (const QString &fileName); 378 | bool save_with_name_plain (const QString &fileName); 379 | 380 | bool open_file (const QString &fileName, bool set_fname = true); 381 | void reload(); 382 | 383 | QString get_triplex(); 384 | void update_title (bool fullname = true); 385 | 386 | void paste(); 387 | 388 | void effects_state_save(); 389 | void effects_state_restore(); 390 | void effects_close_all(); 391 | void effects_update_params(); 392 | }; 393 | 394 | 395 | class CDocumentHolder: public QObject 396 | { 397 | Q_OBJECT 398 | 399 | public: 400 | 401 | CTioHandler tio_handler; 402 | 403 | QString fname_current_session; 404 | 405 | QHash palette; 406 | 407 | QLabel *l_status_bar; 408 | QLabel *l_maintime; 409 | 410 | CTransportControl *transport_control; 411 | 412 | CDocument *current; 413 | 414 | QString dir_config; 415 | QString def_palette; 416 | 417 | QStatusBar *status_bar; 418 | CLogMemo *log; 419 | QList list; 420 | QMainWindow *parent_wnd; 421 | QTabWidget *tab_widget; 422 | 423 | QMenu *recent_menu; 424 | QStringList recent_files; 425 | QString recent_list_fname; 426 | 427 | CDocumentHolder (QObject *parent = 0); 428 | ~CDocumentHolder(); 429 | 430 | CDocument* create_new(); 431 | CDocument* open_file (const QString &fileName, bool set_fname = true); 432 | void reload_recent_list(); 433 | 434 | void save_to_session (const QString &fileName); 435 | void load_from_session (const QString &fileName); 436 | void load_palette (const QString &fileName); 437 | 438 | void close_current(); 439 | void apply_settings(); 440 | void apply_settings_single (CDocument *d); 441 | 442 | void add_to_recent (CDocument *d); 443 | void update_recent_menu(); 444 | 445 | CDocument* get_current(); 446 | 447 | public slots: 448 | 449 | void open_recent(); 450 | }; 451 | 452 | 453 | class CDSP: public QObject 454 | { 455 | 456 | Q_OBJECT 457 | 458 | public: 459 | 460 | float maxl; //for the current nframes 461 | float maxr; 462 | 463 | //mixer stuff 464 | float gain; //in dB 465 | 466 | CFloatBuffer *temp_float_buffer; 467 | 468 | CDSP (QObject *parent = 0); 469 | ~CDSP(); 470 | 471 | // size_t process (CFloatBuffer *fb, size_t nframes); 472 | size_t process (CDocument *d, size_t nframes); 473 | size_t process_rec (float **buffer, size_t channels, size_t nframes); 474 | }; 475 | 476 | 477 | class CFxRackWindow: public QWidget 478 | { 479 | Q_OBJECT 480 | 481 | public: 482 | 483 | CVLevelMeter *level_meter; 484 | QTimer tm_level_meter; 485 | CFxRack *fx_rack; 486 | 487 | QCheckBox cb_l; 488 | QCheckBox cb_r; 489 | 490 | QPushButton *bt_apply; 491 | 492 | CFxRackWindow(); 493 | ~CFxRackWindow(); 494 | 495 | public slots: 496 | 497 | void tm_level_meter_timeout(); 498 | // void apply_fx(); 499 | void cb_l_changed (int value); 500 | void cb_r_changed (int value); 501 | void dial_gain_valueChanged (int value); 502 | 503 | protected: 504 | 505 | void closeEvent (QCloseEvent *event); 506 | 507 | signals: 508 | 509 | void apply_fx_button_pressed(); 510 | 511 | }; 512 | 513 | 514 | #endif 515 | -------------------------------------------------------------------------------- /eko.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * 2010-2021 by Peter Semiletov * 3 | * peter.semiletov@gmail.com * 4 | * * 5 | ***************************************************************************/ 6 | 7 | 8 | #ifndef EKO_H 9 | #define EKO_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | #include "document.h" 28 | #include "logmemo.h" 29 | #include "fman.h" 30 | #include "shortcuts.h" 31 | 32 | 33 | 34 | class CChangeFormatWindow: public QDialog 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | 40 | int fmt; 41 | CWaveform *wf; 42 | 43 | QLabel *file_name; 44 | 45 | QComboBox *cmb_format; 46 | QComboBox *cmb_subtype; 47 | QComboBox *cmb_samplerate; 48 | 49 | QSpinBox *channels; 50 | 51 | CChangeFormatWindow (QWidget *parent, CWaveform *waveform, int fm); 52 | 53 | public slots: 54 | 55 | void format_currentIndexChanged (int index); 56 | }; 57 | 58 | 59 | class CAboutWindow: public QWidget 60 | { 61 | Q_OBJECT 62 | 63 | QLabel *logo; 64 | 65 | public: 66 | 67 | int mascot_x; 68 | bool mascot_right; 69 | 70 | QImage mascot; 71 | CAboutWindow(); 72 | 73 | protected: 74 | 75 | void closeEvent (QCloseEvent *event); 76 | 77 | public slots: 78 | 79 | void update_image(); 80 | 81 | }; 82 | 83 | 84 | class CEKO: public QMainWindow 85 | { 86 | Q_OBJECT 87 | 88 | public: 89 | 90 | CEKO(); 91 | ~CEKO(); 92 | 93 | int fm_entry_mode; 94 | 95 | CShortcuts *shortcuts; 96 | CFMan *fman; 97 | CLogMemo *log; 98 | 99 | CTransportControl *transport_control; 100 | 101 | QString fname_stylesheet; 102 | 103 | bool b_preview; 104 | 105 | int zoom_a; 106 | int zoom_b; 107 | 108 | int idx_tab_edit; 109 | int idx_tab_tune; 110 | int idx_tab_fman; 111 | int idx_tab_learn; 112 | int idx_prev; 113 | 114 | int fman_find_idx; 115 | QList l_fman_find; 116 | 117 | bool ui_update; 118 | 119 | QLabel *l_maintime; 120 | 121 | QToolBar *tb_fman_dir; 122 | QLabel *l_fman_preview; 123 | 124 | QStringList sl_places_bmx; 125 | QStringList sl_urls; 126 | QStringList sl_fif_history; 127 | 128 | QHash programs; 129 | QHash places_bookmarks; 130 | 131 | QTranslator transl_app; 132 | QTranslator transl_system; 133 | 134 | QDir dir_lv; 135 | 136 | QComboBox *cmb_fif; 137 | QCheckBox *cb_play_looped; 138 | QComboBox *cmb_panner; 139 | 140 | 141 | QString man_search_value; 142 | QString opt_shortcuts_string_to_find; 143 | 144 | QString dir_profiles; 145 | QString dir_last; 146 | QString dir_config; 147 | QString dir_sessions; 148 | QString dir_scripts; 149 | QString dir_palettes; 150 | QString dir_themes; 151 | 152 | QString fname_def_palette; 153 | QString fname_fif; 154 | QString fname_places_bookmarks; 155 | QString fname_tempparamfile; 156 | QString fman_fname_to_find; 157 | 158 | QLabel *l_status; 159 | QProgressBar *pb_status; 160 | 161 | 162 | QCheckBox *cb_altmenu; 163 | 164 | QLineEdit *ed_temp_path; 165 | QLineEdit *ed_mp3_encode; 166 | 167 | QComboBox *cmb_src; 168 | QDoubleSpinBox *spb_ogg_q; 169 | 170 | QSpinBox *spb_resample_quality; 171 | 172 | QComboBox *cmb_sound_dev_out; 173 | QComboBox *cmb_sound_dev_in; 174 | 175 | QComboBox *cmb_lng; 176 | 177 | 178 | QMenu *menu_view_themes; 179 | 180 | 181 | protected: 182 | 183 | void closeEvent (QCloseEvent *event); 184 | bool fman_tv_eventFilter (QObject *obj, QEvent *event); 185 | 186 | 187 | private slots: 188 | 189 | /************************* 190 | main window callbacks 191 | *************************/ 192 | 193 | void apply_fx_clicked(); 194 | 195 | 196 | void leaving_tune(); 197 | 198 | void file_import_raw(); 199 | 200 | void fn_insert_silence(); 201 | void fn_silence_selection(); 202 | 203 | void generate_sine(); 204 | void generate_noise(); 205 | 206 | void nav_play_looped(); 207 | 208 | void view_show_mixer(); 209 | 210 | void help_system_check(); 211 | 212 | 213 | void cb_play_looped_changed (int value); 214 | 215 | void cb_show_meterbar_in_db_changed (int value); 216 | void spb_max_undos_valueChanged (int i); 217 | 218 | void slot_transport_play(); 219 | void slot_transport_stop(); 220 | 221 | void cmb_icon_sizes_currentIndexChanged (int index); 222 | 223 | void cmb_sound_dev_out_currentIndexChanged (int index); 224 | void cmb_sound_dev_in_currentIndexChanged (int index); 225 | void cmb_mono_recording_mode_currentIndexChanged (int index); 226 | 227 | void cb_monitor_input_changed (int state); 228 | 229 | 230 | // void cmb_panner_currentIndexChanged (int index); 231 | 232 | 233 | void stop_recording(); 234 | 235 | void fm_full_info(); 236 | 237 | 238 | void fman_refresh(); 239 | void fman_rename(); 240 | void fman_delete(); 241 | void fman_drives_changed (const QString & path); 242 | void fman_current_file_changed (const QString &full_path, const QString &just_name); 243 | void fman_file_activated (const QString &full_path); 244 | void fman_dir_changed (const QString &full_path); 245 | void fman_fname_entry_confirm(); 246 | void fman_create_dir(); 247 | void fman_add_bmk(); 248 | void fman_del_bmk(); 249 | void fman_open(); 250 | void fman_home(); 251 | void fman_places_itemActivated (QListWidgetItem *item); 252 | void fman_select_by_regexp(); 253 | void fman_deselect_by_regexp(); 254 | 255 | void cb_button_saves_as(); 256 | 257 | void pageChanged (int index); 258 | 259 | 260 | void file_record(); 261 | 262 | void newFile(); 263 | void open(); 264 | 265 | void fman_items_select_by_regexp (bool mode); 266 | 267 | void file_reload(); 268 | 269 | void file_export_mp3(); 270 | 271 | 272 | void file_last_opened(); 273 | void file_use_palette(); 274 | void file_open_session(); 275 | void file_save_version(); 276 | void file_change_format(); 277 | 278 | 279 | void cb_altmenu_stateChanged (int state); 280 | 281 | void test(); 282 | 283 | void view_use_profile(); 284 | 285 | bool save(); 286 | bool saveAs(); 287 | 288 | void about(); 289 | void close_current(); 290 | 291 | void ed_copy(); 292 | void ed_copy_to_new(); 293 | void ed_copy_to_new_fmt(); 294 | 295 | void ed_delete(); 296 | 297 | void ed_paste(); 298 | void ed_cut(); 299 | 300 | void ed_undo(); 301 | void ed_redo(); 302 | 303 | void ed_deselect(); 304 | void ed_select_all(); 305 | void ed_trim(); 306 | 307 | 308 | void edit_copy_current_fname(); 309 | 310 | void fn_stereo_to_mono(); 311 | 312 | void fun_51_to_stereo (int algo); 313 | void fn_51_to_stereo_dlike(); 314 | 315 | void fn_51_to_stereo(); 316 | 317 | void fn_mono_to_stereo_half(); 318 | void fn_mono_to_stereo_full(); 319 | void fn_swap_channels(); 320 | 321 | void fn_copy_channel(); 322 | void fn_mute_channel(); 323 | 324 | void fn_fade_out(); 325 | void fn_fade_in(); 326 | 327 | 328 | void fn_stat_rms(); 329 | 330 | void fn_norm(); 331 | void fn_apply_vol_envelope(); 332 | void fn_delete_vol_envelope(); 333 | 334 | void fn_reverse(); 335 | 336 | void fn_detect_average_value(); 337 | 338 | 339 | void fn_dc_offset_detect(); 340 | void fn_dc_offset_fix_manually(); 341 | void fn_dc_offset_fix_auto(); 342 | 343 | void search_find(); 344 | void search_find_next(); 345 | void search_find_prev(); 346 | 347 | void view_toggle_fs(); 348 | void view_stay_on_top(); 349 | 350 | void nav_goto_right_tab(); 351 | void nav_goto_left_tab(); 352 | 353 | 354 | void nav_focus_to_fif(); 355 | void nav_focus_to_editor(); 356 | 357 | void help_show_gpl(); 358 | void help_show_news(); 359 | void help_show_changelog(); 360 | void help_show_todo(); 361 | 362 | void session_save_as(); 363 | 364 | void main_tab_page_changed (int index); 365 | void profile_save_as(); 366 | 367 | void file_info(); 368 | 369 | void man_find_find(); 370 | void man_find_next(); 371 | void man_find_prev(); 372 | 373 | 374 | /************************* 375 | prefs window callbacks 376 | *************************/ 377 | 378 | void spb_def_channels_valueChanged (int i); 379 | 380 | void bt_set_def_format_clicked(); 381 | void pb_choose_temp_path_clicked(); 382 | 383 | 384 | // void cb_locale_override (int state); 385 | //void ed_locale_override_editingFinished(); 386 | void cb_session_restore (int state); 387 | 388 | void cb_use_trad_dialogs_changed (int state); 389 | 390 | // void cmb_proxy_video_decoder_currentIndexChanged (int index); 391 | 392 | 393 | void pb_assign_hotkey_clicked(); 394 | void pb_remove_hotkey_clicked(); 395 | 396 | void slot_lv_menuitems_currentItemChanged (QListWidgetItem *current, QListWidgetItem *previous); 397 | void slot_app_fontname_changed (int index); 398 | 399 | void slot_app_font_size_changed (int i); 400 | void slot_style_currentIndexChanged (int index); 401 | void slot_sl_icons_size_sliderMoved (int value); 402 | 403 | void cmb_buffer_size_frames_currentIndexChanged (int index); 404 | 405 | 406 | void spb_ogg_q_valueChanged (double d); 407 | 408 | void fman_naventry_confirm(); 409 | 410 | void view_use_theme(); 411 | 412 | void cb_zoom_a(); 413 | void cb_zoom_b(); 414 | void save_zoom_a(); 415 | void save_zoom_b(); 416 | void zoom_to_factor(); 417 | void cb_zoom_to_selection(); 418 | 419 | 420 | 421 | private: 422 | 423 | /************************* 424 | main window widgets 425 | *************************/ 426 | 427 | QSplitter *mainSplitter; 428 | QTextBrowser *man; 429 | QPlainTextEdit *log_memo; 430 | QString charset; 431 | 432 | QTabWidget *main_tab_widget; 433 | QTabWidget *tab_options; 434 | QTabWidget *tab_browser; 435 | QTabWidget *tab_widget; 436 | QLineEdit *fif; 437 | 438 | QMenu *fileMenu; 439 | QMenu *editMenu; 440 | 441 | QMenu *menu_file_configs; 442 | QMenu *menu_file_sessions; 443 | QMenu *menu_file_actions; 444 | 445 | QMenu *menu_view_palettes; 446 | QMenu *menu_view_profiles; 447 | 448 | QMenu *menu_fn_sessions; 449 | 450 | 451 | QMenu *menu_zoom; 452 | 453 | QMenu *menu_functions; 454 | 455 | QMenu *menu_fn_channels; 456 | //QMenu *menu_fn_amp; 457 | 458 | 459 | QMenu *menu_file_recent; 460 | QMenu *menu_search; 461 | 462 | QMenu *menu_nav; 463 | QMenu *menu_fm; 464 | QMenu *menu_fm_file_ops; 465 | QMenu *menu_fm_file_infos; 466 | QMenu *menu_view; 467 | 468 | QMenu *helpMenu; 469 | 470 | QToolBar *fileToolBar; 471 | QToolBar *editToolBar; 472 | QToolBar *transportToolBar; 473 | QToolBar *levelMeterToolBar; 474 | 475 | QAction *act_test; 476 | QAction *newAct; 477 | QAction *openAct; 478 | QAction *saveAct; 479 | QAction *saveAsAct; 480 | QAction *exitAct; 481 | QAction *cutAct; 482 | QAction *copyAct; 483 | QAction *closeAct; 484 | QAction *undoAct; 485 | QAction *redoAct; 486 | QAction *pasteAct; 487 | QAction *aboutAct; 488 | QAction *aboutQtAct; 489 | 490 | QAction *transport_play; 491 | QAction *transport_stop; 492 | 493 | 494 | QWidget *w_right; 495 | 496 | QLineEdit *ed_fman_fname; 497 | QComboBox *cb_fman_drives; 498 | 499 | 500 | /************************* 501 | prefs window widgets 502 | *************************/ 503 | 504 | 505 | // QLineEdit *ed_locale_override; 506 | 507 | CShortcutEntry *ent_shtcut; 508 | QListWidget *lv_menuitems; 509 | 510 | 511 | QComboBox *cmb_buffer_size_frames; 512 | 513 | QFontComboBox *cmb_app_font_name; 514 | QSpinBox *spb_app_font_size; 515 | 516 | QLineEdit *ed_fman_path; 517 | QListWidget *lv_places; 518 | QSplitter *spl_fman; 519 | 520 | QTextBrowser *text_file_browser; 521 | 522 | 523 | 524 | 525 | QAction* add_to_menu (QMenu *menu, 526 | const QString &caption, 527 | const char *method, 528 | const QString &shortkt = QString(), 529 | const QString &iconpath = QString() 530 | ); 531 | 532 | 533 | void update_dyn_menus(); 534 | void create_paths(); 535 | 536 | void init_styles(); 537 | 538 | 539 | void handle_args(); 540 | 541 | void update_themes(); 542 | void update_stylesheet (const QString &f); 543 | 544 | void load_palette (const QString &fileName); 545 | 546 | 547 | 548 | void create_main_widget(); 549 | void createActions(); 550 | void createMenus(); 551 | void createOptions(); 552 | 553 | void createManual(); 554 | void updateFonts(); 555 | void update_sessions(); 556 | void update_palettes(); 557 | 558 | void update_places_bookmarks(); 559 | 560 | void update_profiles(); 561 | 562 | void createToolBars(); 563 | void createStatusBar(); 564 | void readSettings(); 565 | void writeSettings(); 566 | 567 | void dragEnterEvent (QDragEnterEvent *event); 568 | void dropEvent (QDropEvent *event); 569 | 570 | void createFman(); 571 | 572 | 573 | QString fif_get_text(); 574 | 575 | void fman_find(); 576 | void fman_find_next(); 577 | void fman_find_prev(); 578 | 579 | void opt_update_keyb(); 580 | 581 | void opt_shortcuts_find(); 582 | void opt_shortcuts_find_next(); 583 | void opt_shortcuts_find_prev(); 584 | 585 | void idx_tab_edit_activate(); 586 | void idx_tab_tune_activate(); 587 | void idx_tab_fman_activate(); 588 | void idx_tab_learn_activate(); 589 | 590 | void show_text_file (const QString &fname); 591 | void show_html_data (const QString &data); 592 | 593 | void fn_ch_mono_to_stereo (bool full); 594 | 595 | }; 596 | 597 | 598 | class CApplication: public QApplication 599 | { 600 | Q_OBJECT 601 | 602 | public: 603 | 604 | CApplication (int &argc, char **argv): QApplication (argc, argv) 605 | {} 606 | 607 | void saveState (QSessionManager &manager); 608 | }; 609 | 610 | 611 | #endif 612 | -------------------------------------------------------------------------------- /eko.pro: -------------------------------------------------------------------------------- 1 | VERSION = 7.1.0 2 | os2: { 3 | DEFINES += 'VERSION_NUMBER=\'"7.1.0"\'' 4 | } else: { 5 | DEFINES += 'VERSION_NUMBER=\\\"$${VERSION}\\\"' 6 | } 7 | 8 | 9 | useclang{ 10 | message ("Clang enabled") 11 | QMAKE_CC=clang 12 | QMAKE_CXX=clang 13 | QMAKE_CXXFLAGS += -std=c++11 14 | } 15 | 16 | 17 | useopencl{ 18 | message ("OpenCL enabled") 19 | LIBS+= -lOpenCL 20 | QMAKE_CXXFLAGS += -std=c++0x 21 | PKGCONFIG += OpenCL 22 | DEFINES += OPENCL_ENABLE 23 | } 24 | 25 | SOURCES += eko.cpp \ 26 | main.cpp \ 27 | document.cpp \ 28 | utils.cpp \ 29 | fman.cpp \ 30 | shortcuts.cpp \ 31 | logmemo.cpp \ 32 | tio.cpp \ 33 | fxset.cpp \ 34 | gui_utils.cpp \ 35 | libretta_interpolator.cpp \ 36 | floatbuffer.cpp \ 37 | envelope.cpp \ 38 | fx-filter.cpp \ 39 | fx-panners.cpp \ 40 | cvlevelmeter.cpp \ 41 | fxrack.cpp \ 42 | afx.cpp \ 43 | fxlist.cpp \ 44 | noisegen.cpp \ 45 | db.cpp \ 46 | fxpresets.cpp 47 | 48 | HEADERS += eko.h \ 49 | document.h \ 50 | utils.h \ 51 | fman.h \ 52 | shortcuts.h \ 53 | logmemo.h \ 54 | tio.h \ 55 | fxset.h \ 56 | gui_utils.h \ 57 | libretta_interpolator.h \ 58 | floatbuffer.h \ 59 | envelope.h \ 60 | fx-filter.h \ 61 | fx-panners.h \ 62 | cvlevelmeter.h \ 63 | fxrack.h \ 64 | afx.h \ 65 | fxlist.h \ 66 | noisegen.h \ 67 | db.h \ 68 | fxpresets.h 69 | 70 | 71 | 72 | TEMPLATE = app 73 | 74 | CONFIG += warn_on \ 75 | thread \ 76 | qt \ 77 | release \ 78 | link_pkgconfig 79 | 80 | QT += core 81 | QT += gui 82 | 83 | greaterThan(QT_MAJOR_VERSION, 4) { 84 | QT += widgets 85 | } else { 86 | #QT += blah blah blah 87 | } 88 | 89 | QMAKE_CXXFLAGS += -std=c++11 90 | 91 | 92 | unix: { 93 | PKGCONFIG += sndfile \ 94 | samplerate \ 95 | portaudio-2.0 96 | } 97 | 98 | 99 | 100 | win32:{ 101 | 102 | isEmpty(PREFIX) { 103 | PREFIX = /usr/local/bin 104 | } 105 | 106 | TARGET = bin/eko 107 | target.path = $$PREFIX 108 | } 109 | 110 | 111 | unix:{ 112 | 113 | isEmpty(PREFIX) { 114 | PREFIX = /usr/local 115 | } 116 | 117 | message(UNIX HERE) 118 | 119 | 120 | #old PREFIX compatibility hack 121 | #message($$replace(PREFIX, bin,)) 122 | #message ($$PREFIX) 123 | PREFIX = $$replace(PREFIX, bin,) 124 | #message ($$PREFIX) 125 | # 126 | 127 | TARGET = bin/eko 128 | target.path = $$PREFIX/bin 129 | desktop.path=$$PREFIX/share/applications 130 | desktop.files=desktop/eko.desktop 131 | 132 | icon64.path = $$PREFIX/share/icons/hicolor/64x64/apps/ 133 | icon64.files += icons/eko.png 134 | } 135 | 136 | 137 | INSTALLS += target desktop icon64 138 | 139 | 140 | RESOURCES += eko.qrc 141 | TRANSLATIONS += translations/ru.ts \ 142 | translations/cs.ts 143 | 144 | DISTFILES += ChangeLog \ 145 | COPYING \ 146 | README \ 147 | NEWS \ 148 | NEWS-RU \ 149 | AUTHORS \ 150 | TODO \ 151 | INSTALL \ 152 | icons/* \ 153 | palettes/* \ 154 | desktop/* \ 155 | manuals/en.html \ 156 | manuals/ru.html \ 157 | translations/* \ 158 | themes/Cotton/stylesheet.css \ 159 | themes/Plum/stylesheet.css \ 160 | themes/Smaragd/stylesheet.css \ 161 | themes/TEA/stylesheet.css \ 162 | themes/Turbo/stylesheet.css \ 163 | themes/Vegan/stylesheet.css 164 | 165 | 166 | 167 | win32: { 168 | 169 | # CONFIG += console 170 | 171 | exists ("c:\\Qt\\Qt5.3.1\\5.3\\mingw482_32\\include\portaudio.h") 172 | { 173 | message ("Portaudio FOUND") 174 | LIBS += -llibportaudio-2 175 | } 176 | 177 | 178 | exists ("c:\\Qt\\Qt5.3.1\\5.3\\mingw482_32\\include\sndfile.h") 179 | { 180 | message ("libsndfile FOUND") 181 | LIBS += -llibsndfile-1 182 | } 183 | 184 | exists ("c:\\Qt\\Qt5.3.1\\5.3\\mingw482_32\\include\samplerate.h") 185 | { 186 | message ("libsamplerate FOUND") 187 | LIBS += -llibsamplerate-0 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /eko.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icons/file-new.png 5 | icons/file-open.png 6 | icons/file-open-active.png 7 | 8 | icons/file-save.png 9 | icons/file-save-active.png 10 | 11 | 12 | icons/file-save-as.png 13 | 14 | icons/edit-copy.png 15 | icons/edit-copy-active.png 16 | 17 | icons/edit-cut.png 18 | icons/edit-cut-active.png 19 | 20 | icons/edit-paste.png 21 | icons/edit-paste-active.png 22 | 23 | icons/create-dir.png 24 | icons/home.png 25 | icons/refresh.png 26 | icons/go.png 27 | 28 | icons/play.png 29 | icons/pause.png 30 | icons/stop.png 31 | icons/search_find.png 32 | 33 | icons/eko.png 34 | 35 | translations/ru.qm 36 | translations/cs.qm 37 | 38 | manuals/en.html 39 | manuals/ru.html 40 | 41 | palettes/EKO 42 | palettes/Vinyl 43 | palettes/Grey 44 | palettes/Spring 45 | palettes/Winter 46 | 47 | themes/TEA/stylesheet.css 48 | themes/Cotton/stylesheet.css 49 | themes/Plum/stylesheet.css 50 | themes/Smaragd/stylesheet.css 51 | themes/Turbo/stylesheet.css 52 | themes/Vegan/stylesheet.css 53 | 54 | 55 | INSTALL 56 | README 57 | NEWS 58 | TODO 59 | NEWS-RU 60 | COPYING 61 | AUTHORS 62 | ChangeLog 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /envelope.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "utils.h" 7 | #include "envelope.h" 8 | 9 | 10 | bool comp_ep (CEnvelopePoint *e1, CEnvelopePoint *e2) 11 | { 12 | return e1->position_frames < e2->position_frames; 13 | } 14 | 15 | 16 | CEnvelopePoint* CEnvelope::find (int frame, int y, int height, int frames_per_section) 17 | { 18 | //foreach (CEnvelopePoint *t, points) 19 | for (auto *t: points) 20 | { 21 | int t_y = get_fvalue (height, t->value); 22 | int t_x = t->position_frames; 23 | 24 | QRect rectangle (t_x, t_y, frames_per_section * ENVELOPE_SIDE, ENVELOPE_SIDE); 25 | 26 | if (rectangle.contains (frame, y)) 27 | return t; 28 | } 29 | 30 | return 0; 31 | } 32 | 33 | 34 | CEnvelopePoint* CEnvelope::get_selected() 35 | { 36 | CEnvelopePoint *p = 0; 37 | 38 | for (int i = 0; i < points.size(); i++) 39 | { 40 | if (points[i]->selected) 41 | { 42 | p = points[i]; 43 | break; 44 | } 45 | } 46 | 47 | return p; 48 | } 49 | 50 | 51 | void CEnvelope::clear() 52 | { 53 | for (int i = 0; i < points.size(); i++) 54 | delete points[i]; 55 | 56 | points.clear(); 57 | } 58 | 59 | 60 | void CEnvelope::select_point (CEnvelopePoint *e) 61 | { 62 | // foreach (CEnvelopePoint *t, points) 63 | for (auto *t: points) 64 | { 65 | t->selected = false; 66 | } 67 | 68 | e->selected = true; 69 | } 70 | 71 | 72 | CEnvelope::~CEnvelope() 73 | { 74 | for (int i = 0; i < points.size(); i++) 75 | delete points[i]; 76 | } 77 | 78 | 79 | void CEnvelope::insert_wise (int x, int y, int height, size_t maximum) 80 | { 81 | CEnvelopePoint *e = new CEnvelopePoint; 82 | 83 | e->position_frames = x; 84 | 85 | if (points.size() == 0) 86 | e->value = 50; 87 | else 88 | e->value = get_percent (height, (float)y); 89 | 90 | if (points.size() == 0) 91 | { 92 | CEnvelopePoint *point_start = new CEnvelopePoint; 93 | 94 | point_start->position_frames = 0; 95 | point_start->value = 50.0f; 96 | 97 | CEnvelopePoint *point_end = new CEnvelopePoint; 98 | 99 | point_end->position_frames = maximum; 100 | point_end->value = 50.0f; 101 | 102 | points.append (point_start); 103 | points.append (e); 104 | points.append (point_end); 105 | 106 | std::stable_sort (points.begin(), points.end(), comp_ep); 107 | 108 | return; 109 | } 110 | 111 | //is there duplicated position? if yes, replace it with a new item 112 | for (int i = 0; i < points.size(); i++) 113 | { 114 | if (e->position_frames == points[i]->position_frames) 115 | { 116 | delete points[i]; 117 | points.removeAt (i); 118 | break; 119 | } 120 | } 121 | 122 | points << e; 123 | 124 | std::stable_sort (points.begin(), points.end(), comp_ep); 125 | 126 | int idx = points.indexOf (e); 127 | 128 | if (idx == 1) 129 | points[0]->value = e->value; 130 | 131 | if (idx == points.size() - 2) 132 | points[points.size()-1]->value = e->value; 133 | } 134 | 135 | 136 | void CEnvelope::point_move (CEnvelopePoint *p, int x, int y, int height) 137 | { 138 | if (! p) 139 | return; 140 | 141 | int idx = points.indexOf (p); 142 | 143 | if ((idx != points.size() - 1) && (idx != 0)) 144 | { 145 | p->position_frames = x; 146 | p->value = get_percent (height, (float)y); 147 | } 148 | else 149 | p->value = get_percent (height, (float)y); 150 | 151 | 152 | //if (idx == 1) 153 | // points[0]->value = p->value; 154 | 155 | 156 | if (idx == points.size() - 2) 157 | points[points.size() - 1]->value = p->value; 158 | 159 | std::stable_sort (points.begin(), points.end(), comp_ep); 160 | } 161 | -------------------------------------------------------------------------------- /envelope.h: -------------------------------------------------------------------------------- 1 | #ifndef ENVELOPE_H 2 | #define ENVELOPE_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #define ENVELOPE_SIDE 20 9 | 10 | 11 | class CEnvelope; 12 | 13 | class CEnvelopePoint: public QObject 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | 19 | size_t position_frames; //frames 20 | float value; 21 | bool selected; 22 | 23 | bool operator <(const CEnvelopePoint &other) const {return position_frames < other.position_frames;} 24 | }; 25 | 26 | 27 | class CEnvelope: public QObject 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | 33 | QList points; 34 | 35 | void insert_wise (int x, int y, int height, size_t maximum = 0); 36 | void select_point (CEnvelopePoint *e); 37 | void point_move (CEnvelopePoint *p, int x, int y, int height); 38 | void clear(); 39 | CEnvelopePoint* get_selected(); 40 | CEnvelopePoint* find (int frame, int y, int height, int frames_per_section); 41 | 42 | ~CEnvelope(); 43 | }; 44 | 45 | 46 | #endif // ENVELOPE_H 47 | -------------------------------------------------------------------------------- /floatbuffer.cpp: -------------------------------------------------------------------------------- 1 | //VER 10 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "floatbuffer.h" 10 | 11 | using namespace std; 12 | 13 | CFloatBuffer::CFloatBuffer (size_t len, size_t channels_count) 14 | { 15 | head = 1; 16 | tail = 0; 17 | 18 | ringbuffer_length = len; 19 | 20 | pbuffer = 0; 21 | channels = channels_count; 22 | length_frames = len; 23 | buffer_interleaved = 0; 24 | samplerate = 0; 25 | sndfile_format = 0; 26 | sndfile_format = sndfile_format | SF_FORMAT_WAV | SF_FORMAT_FLOAT; 27 | 28 | if (channels > FLOAT_BUFFER_MAX_CHANNELS) 29 | channels = FLOAT_BUFFER_MAX_CHANNELS; 30 | 31 | for (size_t ch = 0; ch < channels; ch++) 32 | { 33 | buffer[ch] = new float [length_frames]; 34 | memset (buffer[ch], 0, length_frames * sizeof (float)); 35 | } 36 | } 37 | 38 | 39 | CFloatBuffer::CFloatBuffer (float *interleaved_buffer, size_t len, size_t channels_count) 40 | { 41 | head = 1; 42 | tail = 0; 43 | ringbuffer_length = len; 44 | 45 | pbuffer = 0; 46 | 47 | channels = channels_count; 48 | length_frames = len; 49 | buffer_interleaved = 0; 50 | samplerate = 0; 51 | sndfile_format = 0; 52 | sndfile_format = sndfile_format | SF_FORMAT_WAV | SF_FORMAT_FLOAT; 53 | 54 | if (channels == 1) 55 | { 56 | buffer[0] = interleaved_buffer; 57 | return; 58 | } 59 | 60 | if (channels > FLOAT_BUFFER_MAX_CHANNELS) 61 | channels = FLOAT_BUFFER_MAX_CHANNELS; 62 | 63 | 64 | for (size_t ch = 0; ch < channels; ch++) 65 | { 66 | buffer[ch] = new float [length_frames]; 67 | memset (buffer[ch], 0, length_frames * sizeof (float)); 68 | } 69 | 70 | size_t c = 0; 71 | 72 | for (size_t i = 0; i < length_frames; i++) 73 | { 74 | for (size_t ch = 0; ch < channels; ch++) 75 | { 76 | buffer[ch][i] = interleaved_buffer[c++]; 77 | } 78 | } 79 | 80 | delete [] interleaved_buffer; //we don't need it anymore 81 | } 82 | 83 | 84 | CFloatBuffer::~CFloatBuffer() 85 | { 86 | for (size_t ch = 0; ch < channels; ch++) 87 | delete [] buffer[ch]; 88 | 89 | if (buffer_interleaved) 90 | delete [] buffer_interleaved; 91 | } 92 | 93 | 94 | float* CFloatBuffer::to_interleaved() 95 | { 96 | size_t buflen = length_frames * channels; 97 | 98 | float *interleaved_buffer = new float [buflen]; 99 | 100 | size_t c = 0; 101 | 102 | for (size_t i = 0; i < length_frames; i++) 103 | { 104 | for (size_t ch = 0; ch < channels; ch++) 105 | { 106 | interleaved_buffer[c++] = buffer[ch][i]; 107 | } 108 | } 109 | 110 | return interleaved_buffer; 111 | } 112 | 113 | 114 | CFloatBuffer* CFloatBuffer::clone() 115 | { 116 | CFloatBuffer *fb = new CFloatBuffer (length_frames, channels); 117 | 118 | for (size_t ch = 0; ch < channels; ch++) 119 | { 120 | memcpy (fb->buffer[ch], buffer[ch], length_frames * sizeof (float)); 121 | } 122 | 123 | fb->copy_params (this); 124 | 125 | return fb; 126 | } 127 | 128 | 129 | CFloatBuffer* CFloatBuffer::copy (size_t offset_from, size_t size) 130 | { 131 | if (size > length_frames) 132 | return 0; 133 | 134 | if (offset_from > length_frames) 135 | return 0; 136 | 137 | if (size > (length_frames - offset_from)) 138 | return 0; 139 | 140 | CFloatBuffer *fb = new CFloatBuffer (size, channels); 141 | 142 | fb->copy_params (this); 143 | fb->length_frames = size; 144 | 145 | for (size_t ch = 0; ch < channels; ch++) 146 | { 147 | memcpy (fb->buffer[ch], buffer[ch] + offset_from, size * sizeof (float)); 148 | } 149 | 150 | return fb; 151 | } 152 | 153 | void CFloatBuffer::copy_to_pos (CFloatBuffer *other, size_t offset_from, size_t size, size_t offset_to) 154 | { 155 | if (size > length_frames) 156 | return; 157 | 158 | if (offset_from > length_frames) 159 | return; 160 | 161 | size_t copysize = size; 162 | size_t reminder = length_frames - offset_from; 163 | 164 | if (reminder < size) 165 | copysize = reminder; 166 | 167 | for (size_t ch = 0; ch < channels; ch++) 168 | { 169 | memcpy (other->buffer[ch] + offset_to, buffer[ch] + offset_from, copysize * sizeof (float)); 170 | } 171 | } 172 | 173 | 174 | void CFloatBuffer::copy_channel_to_pos (CFloatBuffer *other, size_t ch_from, size_t ch_to, 175 | size_t offset_from, size_t size, size_t offset_to) 176 | { 177 | if (size > length_frames) 178 | return; 179 | 180 | if (offset_from > length_frames) 181 | return; 182 | 183 | size_t reminder = length_frames - offset_from; 184 | if (reminder < size) 185 | return; 186 | 187 | memcpy (other->buffer[ch_to] + offset_to, buffer[ch_from] + offset_from, size * sizeof (float)); 188 | } 189 | 190 | 191 | void CFloatBuffer::copy_to_pos_with_rate (CFloatBuffer *other, size_t offset_from, size_t size, size_t offset_to, float rate) 192 | { 193 | if (size > length_frames) 194 | return; 195 | 196 | if (offset_from > length_frames) 197 | return; 198 | 199 | size_t reminder = length_frames - offset_from; 200 | if (reminder < size) 201 | return; 202 | 203 | for (size_t ch = 0; ch < channels; ch++) 204 | { 205 | size_t c = 0; 206 | size_t i = 0; 207 | 208 | float *p_dest_buffer = other->buffer[ch] + offset_to; 209 | float *p_source_buffer = buffer[ch] + offset_from; 210 | 211 | while (i < size) 212 | { 213 | p_dest_buffer[c++] = p_source_buffer[(size_t)floor (i * rate)]; 214 | i++; 215 | } 216 | } 217 | } 218 | 219 | 220 | void CFloatBuffer::pbuffer_reset() 221 | { 222 | offset = 0; 223 | 224 | if (pbuffer) 225 | delete [] pbuffer; 226 | 227 | pbuffer = new float* [channels]; 228 | 229 | for (size_t ch = 0; ch < channels; ch++) 230 | { 231 | pbuffer[ch] = buffer[ch]; 232 | } 233 | 234 | } 235 | 236 | 237 | void CFloatBuffer::pbuffer_inc (size_t val) 238 | { 239 | for (size_t ch = 0; ch < channels; ch++) 240 | { 241 | pbuffer[ch] += val; 242 | } 243 | 244 | offset += val; 245 | } 246 | 247 | 248 | void CFloatBuffer::settozero() 249 | { 250 | for (size_t ch = 0; ch < channels; ch++) 251 | { 252 | memset (buffer[ch], 0, length_frames * sizeof (float)); 253 | } 254 | } 255 | 256 | 257 | void CFloatBuffer::allocate_interleaved() 258 | { 259 | if (buffer_interleaved) 260 | delete [] buffer_interleaved; 261 | 262 | buffer_interleaved = new float [length_frames * channels]; 263 | memset (buffer_interleaved, 0, length_frames * channels * sizeof (float)); 264 | } 265 | 266 | 267 | void CFloatBuffer::fill_interleaved() 268 | { 269 | size_t c = 0; 270 | 271 | for (size_t i = 0; i < length_frames; i++) 272 | { 273 | for (size_t ch = 0; ch < channels; ch++) 274 | { 275 | buffer_interleaved[c++] = buffer[ch][i]; 276 | } 277 | } 278 | } 279 | 280 | 281 | //function to overwrite data in this soundbuffer from the other one, 282 | //from the pos position 283 | void CFloatBuffer::overwrite_at (CFloatBuffer *other, size_t pos_frames) 284 | { 285 | if (! other) 286 | return; 287 | 288 | size_t frames_to_copy = other->length_frames; 289 | size_t reminder = length_frames - pos_frames; 290 | 291 | if (frames_to_copy > reminder) 292 | frames_to_copy = reminder; 293 | 294 | for (size_t ch = 0; ch < other->channels; ch++) 295 | { 296 | memcpy (buffer[ch] + pos_frames, other->buffer[ch], frames_to_copy * sizeof (float)); 297 | } 298 | } 299 | 300 | 301 | //convert this sb to stereo and return a new instance 302 | CFloatBuffer* CFloatBuffer::convert_to_stereo (bool full) 303 | { 304 | if (channels != 1) 305 | return 0; 306 | 307 | CFloatBuffer *tfb = new CFloatBuffer (length_frames, 2); 308 | 309 | memcpy (tfb->buffer[0], buffer[0], length_frames * sizeof (float)); 310 | memcpy (tfb->buffer[1], buffer[0], length_frames * sizeof (float)); 311 | 312 | if (! full) 313 | { 314 | for (size_t i = 0; i < length_frames; i++) 315 | { 316 | tfb->buffer[0][i] *= 0.5f; 317 | tfb->buffer[1][i] *= 0.5f; 318 | } 319 | } 320 | 321 | tfb->copy_params (this); 322 | tfb->channels = 2; 323 | 324 | return tfb; 325 | } 326 | 327 | 328 | //the same thing for the mono 329 | //stereo channels are distributed to mono 330 | //with a half level from both channels 331 | CFloatBuffer* CFloatBuffer::convert_to_mono() 332 | { 333 | if (channels != 2) 334 | return 0; 335 | 336 | CFloatBuffer *tfb = new CFloatBuffer (length_frames, 1); 337 | 338 | for (size_t i = 0; i < length_frames; i++) 339 | { 340 | float l = buffer [0][i] * 0.5; 341 | float r = buffer [0][i] * 0.5; 342 | tfb->buffer[0][i] = l + r; 343 | } 344 | 345 | tfb->copy_params (this); 346 | tfb->channels = 1; 347 | 348 | return tfb; 349 | } 350 | 351 | 352 | //returns the resampled data as a new buffer 353 | //the source data remains untouched 354 | CFloatBuffer* CFloatBuffer::resample (size_t new_rate, int resampler) 355 | { 356 | float ratio = (float) 1.0f * new_rate / samplerate; 357 | size_t output_frames = (size_t) floor (length_frames * ratio); 358 | 359 | CFloatBuffer *tfb = new CFloatBuffer (output_frames, channels); 360 | 361 | for (size_t ch = 0; ch < tfb->channels; ch++) 362 | { 363 | SRC_DATA data; 364 | data.src_ratio = ratio; 365 | 366 | data.input_frames = length_frames; 367 | data.output_frames = output_frames; 368 | 369 | data.data_in = buffer[ch]; 370 | data.data_out = tfb->buffer[ch];; 371 | 372 | int error = src_simple (&data, resampler, 1); 373 | if (error) 374 | { 375 | delete tfb; 376 | return 0; 377 | } 378 | } 379 | 380 | //nb->frames = data.output_frames; //REAL LENGTH! 381 | tfb->copy_params (this); 382 | tfb->length_frames = output_frames; 383 | tfb->samplerate = new_rate; 384 | 385 | return tfb; 386 | } 387 | 388 | 389 | //delete data at the range from start to end 390 | CFloatBuffer* CFloatBuffer::delete_range (size_t frames_start, size_t frames_end) 391 | { 392 | size_t delrange = frames_end - frames_start; 393 | size_t new_buffer_frames_count = length_frames - delrange; 394 | 395 | CFloatBuffer *tfb = new CFloatBuffer (new_buffer_frames_count, channels); 396 | 397 | for (size_t ch = 0; ch < channels; ch++) 398 | { 399 | memcpy (tfb->buffer[ch], buffer[ch], frames_start * sizeof (float)); 400 | } 401 | 402 | for (size_t ch = 0; ch < channels; ch++) 403 | { 404 | memcpy (tfb->buffer[ch] + frames_start, buffer[ch] + frames_start + delrange, 405 | (length_frames - frames_end) * sizeof (float)); 406 | } 407 | 408 | tfb->copy_params (this); 409 | tfb->offset = frames_start; 410 | tfb->length_frames = new_buffer_frames_count; 411 | 412 | return tfb; 413 | } 414 | 415 | //copy parameters from "fb" to this sound buffer 416 | void CFloatBuffer::copy_params (CFloatBuffer *fb) 417 | { 418 | if (! fb) 419 | return; 420 | 421 | offset = fb->offset; 422 | samplerate = fb->samplerate; 423 | sndfile_format = fb->sndfile_format; 424 | length_frames = fb->length_frames; 425 | channels = fb->channels; 426 | } 427 | 428 | 429 | //copy all data from "other" to this buffer, including the data parameters 430 | void CFloatBuffer::copy_from (CFloatBuffer *other) 431 | { 432 | if (! other) 433 | return; 434 | 435 | for (size_t ch = 0; ch < channels; ch++) 436 | { 437 | delete [] buffer[ch]; 438 | } 439 | 440 | copy_params (other); 441 | 442 | for (size_t ch = 0; ch < channels; ch++) 443 | { 444 | buffer[ch] = new float [length_frames]; 445 | } 446 | 447 | other->copy_to_pos (this, 0, other->length_frames, 0); 448 | } 449 | 450 | 451 | void CFloatBuffer::copy_from_w_resample (CFloatBuffer *other, int resampler) 452 | { 453 | if (! other || ! other->buffer[0]) 454 | return; 455 | 456 | if (samplerate != other->samplerate) //TEST IT! 457 | { 458 | CFloatBuffer *fb = other->resample (samplerate, resampler); 459 | copy_from (fb); 460 | delete fb; 461 | return; 462 | } 463 | 464 | copy_from (other); 465 | } 466 | 467 | 468 | //paste from "other" to this buffer, at the "pos" position 469 | //resample if it needs to be resampled 470 | 471 | void CFloatBuffer::paste_at (CFloatBuffer *other, size_t pos_frames) 472 | { 473 | if (! other) 474 | return; 475 | 476 | size_t pos_frames_corrected = pos_frames; 477 | if (pos_frames > length_frames) 478 | pos_frames_corrected = length_frames; 479 | 480 | if (samplerate != other->samplerate) //TEST IT! 481 | { 482 | //qDebug() << "TEST IT!"; 483 | CFloatBuffer *fb = other->resample (samplerate); 484 | paste_at (fb, pos_frames_corrected); 485 | delete fb; 486 | return; 487 | } 488 | 489 | CFloatBuffer *temp_buffer = 0; 490 | 491 | if (channels == 1 && other->channels == 2) 492 | temp_buffer = other->convert_to_mono(); 493 | else 494 | if (channels == 2 && other->channels == 1) 495 | temp_buffer = other->convert_to_stereo (false); 496 | else 497 | if (channels == other->channels) 498 | temp_buffer = other->clone(); 499 | 500 | if (! temp_buffer) 501 | return; 502 | 503 | size_t new_buffer_frames_count = temp_buffer->length_frames + length_frames; 504 | 505 | //создаем новый буфер, размером равный текущему со вставляемым 506 | CFloatBuffer *sum = new CFloatBuffer (new_buffer_frames_count, channels); 507 | sum->samplerate = samplerate; 508 | 509 | //из старого буфера в новый, копируем все по позицию position_in_frames 510 | for (size_t ch = 0; ch < channels; ch++) 511 | { 512 | memcpy (sum->buffer[ch], buffer[ch], pos_frames_corrected * sizeof (float)); 513 | } 514 | 515 | //перематываем новый в позицию position_in_frames и копируем в него вставляемый 516 | 517 | for (size_t ch = 0; ch < channels; ch++) 518 | { 519 | memcpy (sum->buffer[ch] + pos_frames_corrected, temp_buffer->buffer[ch], 520 | temp_buffer->length_frames * sizeof (float)); 521 | } 522 | 523 | //перематываем новый в позицию position_in_frames + temp_buffer->float_buffer->length_frames и 524 | // копируем в него остаток старого буфера 525 | 526 | size_t tail = length_frames - pos_frames_corrected; 527 | 528 | cout << "tail: " << tail << endl; 529 | cout << "pos_frames: " << pos_frames_corrected << endl; 530 | //qDebug() << "temp_buffer->length_frames: " << pos_frames; 531 | 532 | 533 | for (size_t ch = 0; ch < channels; ch++) 534 | { 535 | memcpy (sum->buffer[ch] + pos_frames_corrected + temp_buffer->length_frames, 536 | buffer[ch] + pos_frames_corrected, 537 | tail * sizeof (float)); 538 | } 539 | 540 | copy_from (sum); 541 | 542 | delete sum; 543 | delete temp_buffer; 544 | 545 | offset = pos_frames_corrected; 546 | } 547 | 548 | 549 | void CFloatBuffer::ringbuffer_head_inc() 550 | { 551 | head++; 552 | 553 | if (head >= ringbuffer_length) 554 | head = 0; 555 | } 556 | 557 | void CFloatBuffer::ringbuffer_tail_inc() 558 | { 559 | tail++; 560 | 561 | if (tail >= ringbuffer_length) 562 | tail = 0; 563 | } 564 | 565 | 566 | void CFloatBuffer::ringbuffer_set_length (size_t len) 567 | { 568 | ringbuffer_length = len; 569 | 570 | if (ringbuffer_length > length_frames) 571 | ringbuffer_length = length_frames; 572 | } 573 | -------------------------------------------------------------------------------- /floatbuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOATBUFFER_H 2 | #define FLOATBUFFER_H 3 | 4 | //VER 10 5 | 6 | #include 7 | 8 | #define FLOAT_BUFFER_MAX_CHANNELS 8 9 | 10 | 11 | class CFloatBuffer 12 | { 13 | 14 | public: 15 | 16 | float *buffer[FLOAT_BUFFER_MAX_CHANNELS]; 17 | 18 | float **pbuffer; 19 | 20 | float *buffer_interleaved; //for mapping from buffer 21 | 22 | size_t samplerate; 23 | size_t channels; 24 | size_t length_frames; 25 | size_t offset; //of pbuffer or for some puproses 26 | 27 | //ringbuffer: tail index = head - 1 28 | size_t head; //read from here 29 | size_t tail; //write to here 30 | size_t ringbuffer_length; //in the range of length_frames 31 | 32 | int sndfile_format; 33 | 34 | CFloatBuffer (size_t len, size_t channels_count); 35 | CFloatBuffer (float *interleaved_buffer, size_t len, size_t channels_count = 1); 36 | 37 | ~CFloatBuffer(); 38 | 39 | void pbuffer_reset(); 40 | void pbuffer_inc (size_t val); 41 | void settozero(); 42 | 43 | void ringbuffer_head_inc(); 44 | void ringbuffer_tail_inc(); 45 | void ringbuffer_set_length (size_t len); 46 | 47 | void allocate_interleaved(); 48 | void fill_interleaved(); 49 | 50 | float *to_interleaved(); 51 | 52 | CFloatBuffer* clone(); 53 | 54 | CFloatBuffer* copy (size_t offset_from, size_t size); //frames 55 | 56 | void copy_to_pos (CFloatBuffer *other, size_t offset_from, size_t size, size_t offset_to); //frames 57 | void copy_channel_to_pos (CFloatBuffer *other, size_t ch_from, size_t ch_to, 58 | size_t offset_from, size_t size, size_t offset_to); //frames 59 | 60 | void copy_to_pos_with_rate (CFloatBuffer *other, size_t offset_from, size_t size, size_t offset_to, float rate); //frames 61 | 62 | void overwrite_at (CFloatBuffer *other, size_t pos_frames); 63 | 64 | 65 | CFloatBuffer* convert_to_stereo (bool full); 66 | CFloatBuffer* convert_to_mono(); 67 | 68 | CFloatBuffer* resample (size_t new_rate, int resampler = 0); 69 | 70 | CFloatBuffer* delete_range (size_t frames_start, size_t frames_end); 71 | 72 | void copy_params (CFloatBuffer *fb); 73 | void copy_from (CFloatBuffer *other); 74 | void copy_from_w_resample (CFloatBuffer *other, int resampler = 0); 75 | 76 | void paste_at (CFloatBuffer *other, size_t pos_frames); 77 | }; 78 | 79 | #endif // FLOATBUFFER_H 80 | -------------------------------------------------------------------------------- /fman.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * 2007-2022 by Peter Semiletov * 3 | * peter.semiletov@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 3 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 | **************************************************************************/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fman.h" 32 | #include "utils.h" 33 | //#include "logmemo.h" 34 | 35 | 36 | extern QSettings *settings; 37 | 38 | 39 | void CFMan::dir_up() 40 | { 41 | if (dir.isRoot()) 42 | return; 43 | 44 | QString oldcurdir = dir.dirName(); 45 | 46 | dir.cdUp(); 47 | nav (dir.path()); 48 | 49 | QModelIndex index = index_from_name (oldcurdir); 50 | 51 | selectionModel()->setCurrentIndex(index, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 52 | scrollTo (index); 53 | } 54 | 55 | 56 | void CFMan::nav (const QString &path) 57 | { 58 | /*dir.setPath (path); 59 | if (! dir.exists()) 60 | return; 61 | */ 62 | if (file_exists (path)) 63 | dir.setPath (path); 64 | else 65 | dir.setPath (QDir::homePath()); 66 | 67 | if (! dir.exists()) 68 | return; 69 | 70 | setModel (0); 71 | 72 | QDir::SortFlags sort_flags; 73 | 74 | if (sort_order == Qt::DescendingOrder) 75 | sort_flags |= QDir::Reversed; 76 | 77 | if (sort_mode == 0) 78 | sort_flags |= QDir::Name; 79 | 80 | if (sort_mode == 1) 81 | sort_flags |= QDir::Size; 82 | 83 | if (sort_mode == 2) 84 | sort_flags |= QDir::Time; 85 | 86 | sort_flags |= QDir::DirsFirst; 87 | sort_flags |= QDir::IgnoreCase; 88 | sort_flags |= QDir::LocaleAware; 89 | 90 | 91 | mymodel->removeRows (0, mymodel->rowCount()); 92 | 93 | QFileInfoList lst = dir.entryInfoList (QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot | 94 | QDir::Files | QDir::Drives, 95 | sort_flags); 96 | 97 | 98 | 99 | /*QFileInfoList lst = dir.entryInfoList (QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot | 100 | QDir::Files | QDir::Drives, 101 | QDir::Name | 102 | QDir::DirsFirst | QDir::IgnoreCase | QDir::LocaleAware); 103 | 104 | */ 105 | /* 106 | QDir::Name 0x00 Sort by name. 107 | QDir::Time 0x01 Sort by time (modification time). 108 | QDir::Size 0x02 Sort by file size. 109 | QDir::Type 0x80 Sort by file type (extension). 110 | QDir::Unsorted 0x03 Do not sort. 111 | QDir::NoSort -1 Not sorted by default. 112 | QDir::DirsFirst 0x04 Put the directories first, then the files. 113 | QDir::DirsLast 0x20 Put the files first, then the directories. 114 | QDir::Reversed 0x08 Reverse the sort order. 115 | QDir::IgnoreCase 0x10 Sort case-insensitively. 116 | QDir::LocaleAware 0x40 Sort items appropriately using the current locale settings. 117 | 118 | 119 | */ 120 | 121 | #if defined(Q_OS_WIN) || defined(Q_OS_OS2) 122 | 123 | if (path != "/") 124 | append_dot_entry (".."); 125 | 126 | #else 127 | 128 | if (path.size() != 2) 129 | append_dot_entry (".."); 130 | 131 | #endif 132 | 133 | //foreach (QFileInfo fi, lst) 134 | for (const auto &fi: lst) 135 | add_entry (fi); 136 | 137 | setModel (mymodel); 138 | connect (selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(cb_fman_currentChanged(QModelIndex,QModelIndex))); 139 | emit dir_changed (path); 140 | } 141 | 142 | 143 | const QModelIndex CFMan::index_from_name (const QString &name) 144 | { 145 | QList lst = mymodel->findItems (name); 146 | 147 | if (lst.size() > 0) 148 | return mymodel->indexFromItem (lst[0]); 149 | else 150 | return QModelIndex(); 151 | } 152 | 153 | 154 | void CFMan::tv_activated (const QModelIndex &index) 155 | { 156 | QString item_string = index.data().toString(); 157 | 158 | QString dpath = dir.path(); 159 | 160 | if (dpath.size() > 1) 161 | if (dpath.endsWith("/") || dpath.endsWith("\\")) 162 | dpath.truncate(dpath.size() - 1); 163 | 164 | QString full_path; 165 | 166 | if (dpath == "/") 167 | full_path = "/" + item_string; 168 | else 169 | full_path = dpath + "/" + item_string; 170 | 171 | if (item_string == ".." && dir.path() != "/") 172 | { 173 | dir_up(); 174 | return; 175 | } 176 | 177 | if (is_dir (full_path)) 178 | { 179 | nav (full_path); 180 | QModelIndex index = mymodel->index (0, 0); 181 | selectionModel()->setCurrentIndex (index, QItemSelectionModel::Select | 182 | QItemSelectionModel::Rows); 183 | 184 | return; 185 | } 186 | else 187 | emit file_activated (full_path); 188 | } 189 | 190 | 191 | void CFMan::add_entry (const QFileInfo &fi) 192 | { 193 | QList items; 194 | 195 | QStandardItem *item = new QStandardItem (fi.fileName()); 196 | 197 | if (fi.isDir()) 198 | { 199 | QFont f = item->font(); 200 | f.setBold (true); 201 | item->setFont(f); 202 | } 203 | 204 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); 205 | items.append (item); 206 | 207 | item = new QStandardItem (QString::number (fi.size())); 208 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled); 209 | items.append (item); 210 | 211 | item = new QStandardItem (fi.lastModified().toString ("yyyy-MM-dd")); 212 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled); 213 | items.append (item); 214 | 215 | mymodel->appendRow (items); 216 | } 217 | 218 | 219 | void CFMan::append_dot_entry (const QString &fname) 220 | { 221 | QList items; 222 | 223 | QStandardItem *item = new QStandardItem (fname); 224 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled); 225 | items.append (item); 226 | 227 | item = new QStandardItem ("-"); 228 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled); 229 | items.append (item); 230 | 231 | item = new QStandardItem ("-"); 232 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled); 233 | items.append (item); 234 | 235 | mymodel->appendRow (items); 236 | } 237 | 238 | 239 | void CFMan::header_view_sortIndicatorChanged (int logicalIndex, Qt::SortOrder order) 240 | { 241 | // qDebug() << "header col = " << logicalIndex << " order = " << order; 242 | sort_order = order; 243 | sort_mode = logicalIndex; 244 | 245 | settings->setValue ("fman_sort_mode", sort_mode); 246 | settings->setValue ("fman_sort_order", sort_order); 247 | 248 | refresh(); 249 | } 250 | 251 | 252 | CFMan::CFMan (QWidget *parent): QTreeView (parent) 253 | { 254 | sort_mode = settings->value ("fman_sort_mode", 0).toInt(); 255 | sort_order = Qt::SortOrder (settings->value ("fman_sort_order", 0).toInt()); 256 | 257 | mymodel = new QStandardItemModel (0, 3, parent); 258 | 259 | mymodel->setHeaderData (0, Qt::Horizontal, QObject::tr ("Name")); 260 | mymodel->setHeaderData (1, Qt::Horizontal, QObject::tr ("Size")); 261 | mymodel->setHeaderData (2, Qt::Horizontal, QObject::tr ("Modified at")); 262 | 263 | setRootIsDecorated (false); 264 | setAlternatingRowColors (true); 265 | setAllColumnsShowFocus (true); 266 | setModel (mymodel); 267 | setDragEnabled (true); 268 | 269 | 270 | #if QT_VERSION >= 0x050000 271 | 272 | header()->setSectionResizeMode (QHeaderView::ResizeToContents); 273 | header()->setSectionsClickable (true); 274 | 275 | #else 276 | 277 | header()->setResizeMode (QHeaderView::ResizeToContents); 278 | header()->setClickable (true); 279 | 280 | #endif 281 | 282 | header()->setSortIndicator (sort_mode, sort_order); 283 | header()->setSortIndicatorShown (true); 284 | 285 | connect (header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(header_view_sortIndicatorChanged(int,Qt::SortOrder))); 286 | 287 | header()->setStretchLastSection (false); 288 | 289 | setSelectionMode (QAbstractItemView::ExtendedSelection); 290 | setSelectionBehavior (QAbstractItemView::SelectRows); 291 | 292 | connect (this, SIGNAL(activated(QModelIndex)), this, SLOT(tv_activated(QModelIndex))); 293 | } 294 | 295 | 296 | void CFMan::cb_fman_currentChanged (const QModelIndex ¤t, const QModelIndex &previous ) 297 | { 298 | int row = current.row(); 299 | if (row < 0) 300 | { 301 | emit current_file_changed ("", ""); 302 | return; 303 | } 304 | 305 | QModelIndex i = model()->index (row, 0); 306 | 307 | QString item_string = i.data().toString(); 308 | 309 | QString full_path = dir.path() + "/" + item_string; 310 | 311 | QFileInfo f (full_path); 312 | 313 | //qDebug() << "full_path:" << full_path; 314 | //qDebug() << "is exists: " << f.exists(); 315 | 316 | // qDebug() << "is file: " << f.isFile(); 317 | // qDebug() << "is dir: " << f.isDir(); 318 | 319 | //qDebug() << "IS DIR: " << full_path << " " << is_dir (full_path); 320 | 321 | // if (! is_dir (full_path)) 322 | emit current_file_changed (full_path, item_string); 323 | } 324 | 325 | 326 | QString CFMan::get_sel_fname() 327 | { 328 | if (! selectionModel()->hasSelection()) 329 | return QString(); 330 | 331 | QModelIndex index = selectionModel()->currentIndex(); 332 | QString item_string = index.data().toString(); 333 | return dir.path() + "/" + item_string; //return the full path 334 | } 335 | 336 | 337 | QStringList CFMan::get_sel_fnames() 338 | { 339 | if (! selectionModel()->hasSelection()) 340 | return QStringList(); 341 | 342 | QModelIndexList il = selectionModel()->QItemSelectionModel::selectedRows (0); 343 | QStringList li; 344 | 345 | //foreach (QModelIndex index, il) 346 | for (auto index: il) 347 | { 348 | QString item_string = index.data().toString(); 349 | if (item_string != "..") 350 | { 351 | QString full_path = dir.path() + "/" + item_string; 352 | li.append (full_path); 353 | } 354 | } 355 | 356 | return li; 357 | } 358 | 359 | 360 | void CFMan::refresh() 361 | { 362 | QString current; 363 | 364 | if (selectionModel()->hasSelection()) 365 | { 366 | QModelIndex index = selectionModel()->currentIndex(); 367 | current = index.data().toString(); 368 | } 369 | 370 | nav (dir.path()); 371 | 372 | QModelIndex index = index_from_name (current); 373 | selectionModel()->setCurrentIndex (index, QItemSelectionModel::Select | QItemSelectionModel::Rows); 374 | scrollTo (index); 375 | } 376 | 377 | 378 | const QModelIndex CFMan::index_from_idx (int idx) 379 | { 380 | QStandardItem *item = mymodel->item (idx); 381 | if (item) 382 | return mymodel->indexFromItem (item); 383 | else 384 | return QModelIndex(); 385 | } 386 | 387 | 388 | int CFMan::get_sel_index() 389 | { 390 | if (! selectionModel()->hasSelection()) 391 | return -1; 392 | 393 | QModelIndex index = selectionModel()->currentIndex(); 394 | return index.row(); 395 | } 396 | 397 | 398 | void CFMan::mouseMoveEvent (QMouseEvent *event) 399 | { 400 | if (! (event->buttons() & Qt::LeftButton)) 401 | return; 402 | 403 | QStringList l = get_sel_fnames(); 404 | if (l.size() < 1) 405 | return; 406 | 407 | QDrag *drag = new QDrag (this); 408 | QMimeData *mimeData = new QMimeData; 409 | 410 | QList list; 411 | 412 | //foreach (QString fn, l) 413 | for (const auto &fn: l) 414 | list.append (QUrl::fromLocalFile (fn)); 415 | 416 | mimeData->setUrls (list); 417 | drag->setMimeData (mimeData); 418 | 419 | if (drag->exec (Qt::CopyAction | 420 | Qt::MoveAction | 421 | Qt::LinkAction) == Qt::MoveAction) 422 | refresh(); 423 | 424 | event->accept(); 425 | } 426 | 427 | 428 | void CFMan::keyPressEvent (QKeyEvent *event) 429 | { 430 | /* if (event->key() == Qt::Key_Insert) 431 | { 432 | bool sel = false; 433 | QModelIndex index = selectionModel()->currentIndex(); 434 | int row = index.row(); 435 | 436 | if (selectionModel()->isSelected (index)) 437 | sel = true; 438 | 439 | sel = ! sel; 440 | 441 | if (sel) 442 | selectionModel()->select (index, QItemSelectionModel::Select | QItemSelectionModel::Rows); 443 | else 444 | selectionModel()->select (index, QItemSelectionModel::Deselect | QItemSelectionModel::Rows); 445 | 446 | 447 | if (row < mymodel->rowCount() - 1) 448 | { 449 | QModelIndex newindex = mymodel->index (++row, 0); 450 | selectionModel()->setCurrentIndex (newindex, QItemSelectionModel::Current | QItemSelectionModel::Rows); 451 | scrollTo (newindex); 452 | } 453 | 454 | event->accept(); 455 | return; 456 | } 457 | 458 | 459 | if (event->key() == Qt::Key_Backspace) 460 | { 461 | dir_up(); 462 | event->accept(); 463 | return; 464 | } 465 | 466 | 467 | if (event->key() == Qt::Key_Return) 468 | { 469 | tv_activated (currentIndex()); 470 | event->accept(); 471 | return; 472 | } 473 | 474 | 475 | if (event->key() == Qt::Key_Up) 476 | { 477 | if (currentIndex().row() == 0) 478 | { 479 | event->accept(); 480 | return; 481 | } 482 | 483 | selectionModel()->setCurrentIndex (indexAbove (currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 484 | event->accept(); 485 | return; 486 | } 487 | 488 | 489 | if (event->key() == Qt::Key_Down) 490 | { 491 | if (currentIndex().row() == mymodel->rowCount() - 1) 492 | { 493 | event->accept(); 494 | return; 495 | } 496 | 497 | selectionModel()->setCurrentIndex (indexBelow(currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 498 | event->accept(); 499 | return; 500 | } 501 | 502 | 503 | if (event->key() == Qt::Key_PageUp) 504 | { 505 | QModelIndex idx = moveCursor (QAbstractItemView::MovePageUp, Qt::NoModifier); 506 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 507 | event->accept(); 508 | return; 509 | } 510 | 511 | 512 | if (event->key() == Qt::Key_PageDown) 513 | { 514 | QModelIndex idx = moveCursor (QAbstractItemView::MovePageDown, Qt::NoModifier); 515 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 516 | event->accept(); 517 | return; 518 | } 519 | 520 | 521 | if (event->key() == Qt::Key_End) 522 | { 523 | QModelIndex idx = mymodel->index (mymodel->rowCount() - 1, 0); 524 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate ); 525 | event->accept(); 526 | return; 527 | } 528 | 529 | 530 | if (event->key() == Qt::Key_Home) 531 | { 532 | QModelIndex idx = mymodel->index (0, 0); 533 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 534 | event->accept(); 535 | return; 536 | } 537 | 538 | 539 | QTreeView::keyPressEvent (event);*/ 540 | if (event->key() == Qt::Key_Insert) 541 | { 542 | if (currentIndex().row() == mymodel->rowCount() - 1) 543 | { 544 | event->accept(); 545 | return; 546 | } 547 | 548 | selectionModel()->setCurrentIndex (indexBelow (currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::Toggle); 549 | 550 | event->accept(); 551 | return; 552 | } 553 | 554 | 555 | if (event->key() == Qt::Key_Backspace) 556 | { 557 | dir_up(); 558 | event->accept(); 559 | return; 560 | } 561 | 562 | 563 | if (event->key() == Qt::Key_Return) 564 | { 565 | tv_activated (currentIndex()); 566 | event->accept(); 567 | return; 568 | } 569 | 570 | 571 | if (event->key() == Qt::Key_Up) 572 | { 573 | if (currentIndex().row() == 0) 574 | { 575 | event->accept(); 576 | return; 577 | } 578 | 579 | 580 | if (event->modifiers() & Qt::ShiftModifier) 581 | selectionModel()->setCurrentIndex (indexAbove (currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::Toggle); 582 | else 583 | selectionModel()->setCurrentIndex (indexAbove (currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 584 | 585 | event->accept(); 586 | return; 587 | } 588 | 589 | 590 | if (event->key() == Qt::Key_Down) 591 | { 592 | if (currentIndex().row() == mymodel->rowCount() - 1) 593 | { 594 | event->accept(); 595 | return; 596 | } 597 | 598 | if (event->modifiers() & Qt::ShiftModifier) 599 | selectionModel()->setCurrentIndex (indexBelow (currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::Toggle); 600 | else 601 | selectionModel()->setCurrentIndex (indexBelow(currentIndex()), QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 602 | 603 | event->accept(); 604 | return; 605 | } 606 | 607 | 608 | if (event->key() == Qt::Key_PageUp) 609 | { 610 | QModelIndex idx = moveCursor (QAbstractItemView::MovePageUp, Qt::NoModifier); 611 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 612 | event->accept(); 613 | return; 614 | } 615 | 616 | 617 | if (event->key() == Qt::Key_PageDown) 618 | { 619 | QModelIndex idx = moveCursor (QAbstractItemView::MovePageDown, Qt::NoModifier); 620 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 621 | event->accept(); 622 | return; 623 | } 624 | 625 | 626 | if (event->key() == Qt::Key_End) 627 | { 628 | QModelIndex idx = mymodel->index (mymodel->rowCount() - 1, 0); 629 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate ); 630 | event->accept(); 631 | return; 632 | } 633 | 634 | if (event->key() == Qt::Key_Home) 635 | { 636 | QModelIndex idx = mymodel->index (0, 0); 637 | selectionModel()->setCurrentIndex (idx, QItemSelectionModel::Rows | QItemSelectionModel::NoUpdate); 638 | event->accept(); 639 | return; 640 | } 641 | 642 | 643 | QTreeView::keyPressEvent (event); 644 | } 645 | 646 | 647 | void CFMan::drawRow (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 648 | { 649 | if (index.row() == currentIndex().row()) 650 | { 651 | QStyleOptionViewItem current_option = option; 652 | QTreeView::drawRow (painter, current_option, index); 653 | 654 | QStyleOptionFocusRect o; 655 | o.rect = option.rect.adjusted(1,1,-1,-1); 656 | o.state |= QStyle::State_KeyboardFocusChange; 657 | o.state |= QStyle::State_Item; 658 | 659 | //o.backgroundColor = palette().color(QPalette::Background); 660 | //o.backgroundColor = QColor ("red"); 661 | 662 | QApplication::style()->drawPrimitive (QStyle::PE_FrameFocusRect, &o, painter); 663 | 664 | QRect r = option.rect.adjusted (1, 1, -1,-1); 665 | painter->drawRect (r); 666 | } 667 | else 668 | QTreeView::drawRow (painter, option, index); 669 | } 670 | -------------------------------------------------------------------------------- /fman.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * 2007-2018 by Peter Semiletov * 3 | * peter.semiletov@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 3 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 | **************************************************************************/ 20 | 21 | 22 | #ifndef FMAN_H 23 | #define FMAN_H 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | class CFMan: public QTreeView 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | 41 | QDir dir; 42 | 43 | int sort_mode; 44 | Qt::SortOrder sort_order; 45 | 46 | QStandardItemModel *mymodel; 47 | QList list; 48 | 49 | CFMan (QWidget *parent = 0); 50 | 51 | void add_entry (const QFileInfo &fi); 52 | void append_dot_entry (const QString &fname); 53 | 54 | const QModelIndex index_from_name (const QString &name); 55 | const QModelIndex index_from_idx (int idx); 56 | int get_sel_index(); 57 | 58 | void nav (const QString &path); 59 | 60 | QString get_sel_fname(); 61 | QStringList get_sel_fnames(); 62 | 63 | public slots: 64 | 65 | void tv_activated (const QModelIndex &index); 66 | void refresh(); 67 | void dir_up(); 68 | void cb_fman_currentChanged (const QModelIndex ¤t, const QModelIndex &previous); 69 | void header_view_sortIndicatorChanged (int logicalIndex, Qt::SortOrder order); 70 | 71 | signals: 72 | 73 | void file_activated (const QString &path); 74 | void dir_changed (const QString &path); 75 | void current_file_changed (const QString &path, const QString &just_name); 76 | 77 | protected: 78 | 79 | void mouseMoveEvent (QMouseEvent *event); 80 | void keyPressEvent (QKeyEvent *event); 81 | void drawRow (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /fx-filter.cpp: -------------------------------------------------------------------------------- 1 | #include "fx-filter.h" 2 | 3 | /* 4 | 5 | this code based on Martin Finke's filter tutorial, 6 | where the filter itself based on the resonant filter 7 | by Paul Kellett http://www.musicdsp.org/showone.php?id=29 8 | */ 9 | 10 | float CFilter::process (float sample, size_t channel) 11 | { 12 | if (channel == 0) 13 | { 14 | bufl0 += cutoff * (sample - bufl0 + feedback_amount * (bufl0 - bufl1)); //add reso 15 | bufl1 += cutoff * (bufl0 - bufl1); 16 | 17 | bufl2 += cutoff * (bufl1 - bufl2); 18 | bufl3 += cutoff * (bufl2 - bufl3); 19 | 20 | switch (mode) 21 | { 22 | case FILTER_MODE_LOWPASS: 23 | return bufl1; 24 | 25 | case FILTER_MODE_HIGHPASS: 26 | return sample - bufl0; 27 | 28 | case FILTER_MODE_BANDPASS: 29 | return bufl0 - bufl3; 30 | 31 | default: 32 | return 0.0f; 33 | } 34 | } 35 | else 36 | { 37 | bufr0 += cutoff * (sample - bufr0 + feedback_amount * (bufr0 - bufr1)); //add reso 38 | bufr1 += cutoff * (bufr0 - bufr1); 39 | 40 | bufr2 += cutoff * (bufr1 - bufr2); 41 | bufr3 += cutoff * (bufr2 - bufr3); 42 | 43 | switch (mode) 44 | { 45 | case FILTER_MODE_LOWPASS: 46 | return bufr1; 47 | 48 | case FILTER_MODE_HIGHPASS: 49 | return sample - bufr0; 50 | 51 | case FILTER_MODE_BANDPASS: 52 | return bufr0 - bufr3; 53 | 54 | default: 55 | return 0.0f; 56 | } 57 | 58 | } 59 | 60 | return 0.0f; 61 | } 62 | 63 | 64 | CFilter::CFilter() 65 | { 66 | cutoff = 0.99f; 67 | resonance = 0.0f; 68 | mode = FILTER_MODE_LOWPASS; 69 | 70 | bufl0 = 0.0f; 71 | bufl1 = 0.0f; 72 | bufl2 = 0.0f; 73 | bufl3 = 0.0f; 74 | bufr0 = 0.0f; 75 | bufr1 = 0.0f; 76 | bufr2 = 0.0f; 77 | bufr3 = 0.0f; 78 | 79 | calc_feedback_amount(); 80 | } 81 | 82 | void CFilter::reset() 83 | { 84 | bufl0 = 0.0f; 85 | bufl1 = 0.0f; 86 | bufl2 = 0.0f; 87 | bufl3 = 0.0f; 88 | bufr0 = 0.0f; 89 | bufr1 = 0.0f; 90 | bufr2 = 0.0f; 91 | bufr3 = 0.0f; 92 | 93 | calc_feedback_amount(); 94 | } 95 | -------------------------------------------------------------------------------- /fx-filter.h: -------------------------------------------------------------------------------- 1 | #ifndef FXFILTER_H 2 | #define FXFILTER_H 3 | 4 | /* 5 | 6 | this code based on Martin Finke's filter tutorial, 7 | where the filter itself based on the resonant filter 8 | by Paul Kellett http://www.musicdsp.org/showone.php?id=29 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | enum filter_mode { 15 | FILTER_MODE_LOWPASS = 0, 16 | FILTER_MODE_HIGHPASS, 17 | FILTER_MODE_BANDPASS 18 | }; 19 | 20 | class CFilter 21 | { 22 | public: 23 | 24 | float resonance; 25 | int mode; 26 | float feedback_amount; 27 | float cutoff; 28 | 29 | float bufl0; 30 | float bufl1; 31 | float bufl2; 32 | float bufl3; 33 | float bufr0; 34 | float bufr1; 35 | float bufr2; 36 | float bufr3; 37 | 38 | CFilter(); 39 | 40 | void reset(); 41 | float process (float sample, size_t channel); 42 | inline void set_cutoff (float v) {cutoff = v; calc_feedback_amount();}; 43 | inline void set_resonance (float v) {resonance = v; calc_feedback_amount();}; 44 | inline void calc_feedback_amount() {feedback_amount = resonance + resonance / (1.0 - cutoff);}; 45 | 46 | }; 47 | 48 | 49 | 50 | #endif // FXFILTER_H 51 | -------------------------------------------------------------------------------- /fx-panners.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/fx-panners.cpp -------------------------------------------------------------------------------- /fx-panners.h: -------------------------------------------------------------------------------- 1 | #ifndef FXPANNERS_H 2 | #define FXPANNERS_H 3 | 4 | 5 | //linear panner, law: -6 dB 6 | inline void pan_linear6 (float &l, float& r, float p) 7 | { 8 | l = 1 - p; 9 | r = p; 10 | } 11 | 12 | 13 | //linear panner, law: 0 dB 14 | inline void pan_linear0 (float &l, float& r, float p) 15 | { 16 | l = 0.5 + (1 - p); 17 | r = 0.5 + p; 18 | } 19 | 20 | 21 | //square root panner, law: -3 dB 22 | inline void pan_sqrt (float &l, float& r, float p) 23 | { 24 | l = sqrt (1 - p); 25 | r = sqrt (p); 26 | } 27 | 28 | 29 | //sin/cos panner, law: -3 dB 30 | inline void pan_sincos (float &l, float& r, float p) 31 | { 32 | float pan = 0.5 * M_PI * p; 33 | l = cos (pan); 34 | r = sin (pan); 35 | } 36 | 37 | inline void pan_sincos_v2 (float &l, float& r, float p) 38 | { 39 | float pan = p * M_PI / 2; 40 | l = l * sin (pan); 41 | r = r * cos (pan); 42 | } 43 | 44 | 45 | #endif // FXPANNERS_H 46 | -------------------------------------------------------------------------------- /fxlist.cpp: -------------------------------------------------------------------------------- 1 | #include "fxlist.h" 2 | #include "fxset.h" 3 | 4 | CFxList::CFxList() 5 | { 6 | /*list.append (new CFxSimpleAmp); 7 | list.append (new CFxSimpleOverdrive); 8 | list.append (new CFxDelay); 9 | list.append (new CFxSimpleFilter); 10 | list.append (new CFxVynil); 11 | list.append (new CFxMetaluga); 12 | list.append (new CFxJest); 13 | */ 14 | modulenames[CFxSimpleAmp::get_modulename()] = CFxSimpleAmp::create_self; 15 | modulenames[CFxSimpleOverdrive::get_modulename()] = CFxSimpleOverdrive::create_self; 16 | modulenames[CFxDelay::get_modulename()] = CFxDelay::create_self; 17 | modulenames[CFxSimpleFilter::get_modulename()] = CFxSimpleFilter::create_self; 18 | modulenames[CFxVynil::get_modulename()] = CFxVynil::create_self; 19 | modulenames[CFxMetaluga::get_modulename()] = CFxMetaluga::create_self; 20 | modulenames[CFxJest::get_modulename()] = CFxJest::create_self; 21 | 22 | 23 | classnames["CFxSimpleAmp"] = CFxSimpleAmp::create_self; 24 | classnames["CFxSimpleOverdrive"] = CFxSimpleOverdrive::create_self; 25 | classnames["CFxDelay"] = CFxDelay::create_self; 26 | classnames["CFxSimpleFilter"] = CFxSimpleFilter::create_self; 27 | classnames["CFxVynil"] = CFxVynil::create_self; 28 | classnames["CFxMetaluga"] = CFxMetaluga::create_self; 29 | classnames["CFxJest"] = CFxJest::create_self; 30 | 31 | } 32 | 33 | 34 | CFxList::~CFxList() 35 | { 36 | /*foreach (AFx *f, list) 37 | { 38 | delete f; 39 | }*/ 40 | } 41 | 42 | 43 | AFx *CFxList::find_by_name (const QString &fxname) 44 | { 45 | /*for (int i = 0; i < list.size(); i++) 46 | { 47 | if (list[i]->name == fxname) 48 | return list[i]; 49 | } 50 | 51 | return 0;*/ 52 | return modulenames[fxname](); 53 | } 54 | 55 | 56 | 57 | QStringList CFxList::names() 58 | { 59 | /* QStringList l; 60 | foreach (AFx *f, list) 61 | l.append (f->name); 62 | return l; */ 63 | 64 | QStringList l = modulenames.keys(); 65 | l.sort(); 66 | return l; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /fxlist.h: -------------------------------------------------------------------------------- 1 | #ifndef FXLIST_H 2 | #define FXLIST_H 3 | 4 | #include 5 | 6 | 7 | #include "afx.h" 8 | 9 | typedef AFx* (*t_fx_creator)(); 10 | 11 | 12 | //available fx 13 | class CFxList: public QObject 14 | { 15 | public: 16 | 17 | QHash modulenames; 18 | QHash classnames; 19 | 20 | CFxList(); 21 | ~CFxList(); 22 | 23 | AFx *find_by_name (const QString &fxname); 24 | QStringList names(); 25 | }; 26 | 27 | 28 | #endif // FXLIST_H 29 | -------------------------------------------------------------------------------- /fxpresets.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "fxpresets.h" 9 | #include "utils.h" 10 | #include "gui_utils.h" 11 | 12 | 13 | CFxPresets::CFxPresets (QWidget *parent): QWidget (parent) 14 | { 15 | 16 | QHBoxLayout *h_box = new QHBoxLayout; 17 | setLayout (h_box); 18 | 19 | cmb_presets = new QComboBox; 20 | QPushButton *bt_menu = new QPushButton (tr ("Menu")); 21 | 22 | h_box->addWidget (cmb_presets); 23 | h_box->addWidget (bt_menu); 24 | 25 | connect (cmb_presets, SIGNAL(currentIndexChanged(QString)), 26 | this, SLOT(cmb_presets_currentIndexChanged(QString))); 27 | 28 | 29 | menu_banks = new QMenu (tr ("Banks")); 30 | 31 | menu = new QMenu; 32 | bt_menu->setMenu (menu); 33 | 34 | menu->addMenu (menu_banks); 35 | 36 | menu_add_item (this, menu, tr ("Bank new"), SLOT (bank_new_click()), "", ""); 37 | menu_add_item (this, menu, tr ("Bank load"), SLOT (bank_load_click()), "", ""); 38 | menu_add_item (this, menu, tr ("Bank save"), SLOT (bank_save_click()), "", ""); 39 | menu_add_item (this, menu, tr ("Bank save as"), SLOT (bank_save_as_click()), "", ""); 40 | 41 | menu_add_item (this, menu, tr ("Preset save"), SLOT (preset_save()), "", ""); 42 | menu_add_item (this, menu, tr ("Preset save as"), SLOT (preset_save_as()), "", ""); 43 | } 44 | 45 | 46 | void CFxPresets::load_bank_file (const QString &fname) 47 | { 48 | if (fname.isNull() || fname.isEmpty()) 49 | return; 50 | 51 | cmb_presets->clear(); 52 | map.clear(); 53 | map = map_load_keyval (fname, "^I^S^"); 54 | 55 | cmb_presets->addItems (map.keys()); 56 | } 57 | 58 | 59 | void CFxPresets::save_bank_file (const QString &fname) 60 | { 61 | if (fname.startsWith (":")) 62 | return; 63 | 64 | // qDebug() << "CFxPresets::save_bank_file " << fname; 65 | 66 | QString s = map_keyval_to_string (map, "^I^S^"); 67 | 68 | //qDebug() << s; 69 | 70 | qstring_save (fname, s); 71 | } 72 | 73 | 74 | void CFxPresets::cmb_presets_currentIndexChanged (const QString &text) 75 | { 76 | emit preset_changed (map[text]); 77 | } 78 | 79 | 80 | void CFxPresets::bank_new_click() 81 | { 82 | path_bank = ""; 83 | map.clear(); 84 | cmb_presets->clear(); 85 | } 86 | 87 | 88 | void CFxPresets::bank_save_click() 89 | { 90 | if (! file_exists (path_bank) || path_bank.indexOf (":") == 0) 91 | bank_save_as_click(); 92 | else 93 | save_bank_file (path_bank); 94 | } 95 | 96 | 97 | void CFxPresets::bank_save_as_click() 98 | { 99 | create_bank_dir(); 100 | 101 | QString f = QFileDialog::getSaveFileName (this, tr ("Save File"), banks_path); 102 | if (f.isNull()) 103 | return; 104 | 105 | path_bank = f; 106 | save_bank_file (path_bank); 107 | 108 | menu_banks->clear(); 109 | update_banks_list (banks_path); 110 | } 111 | 112 | 113 | void CFxPresets::bank_load_click() 114 | { 115 | QString f = QFileDialog::getOpenFileName (this, tr ("Open File"), banks_path); 116 | if (f.isNull()) 117 | return; 118 | 119 | path_bank = f; 120 | load_bank_file (banks_path); 121 | } 122 | 123 | 124 | void CFxPresets::preset_save_as() 125 | { 126 | bool ok; 127 | QString text = QInputDialog::getText(this, tr("Save preset as"), 128 | tr("Name:"), QLineEdit::Normal, 129 | "", &ok); 130 | if (ok && !text.isEmpty()) 131 | { 132 | emit save_request(); 133 | map[text] = preset_data; 134 | cmb_presets->addItem (text); 135 | } 136 | } 137 | 138 | 139 | void CFxPresets::preset_save() 140 | { 141 | if (cmb_presets->currentText().isNull()) 142 | { 143 | preset_save_as(); 144 | return; 145 | } 146 | 147 | emit save_request(); 148 | map[cmb_presets->currentText()] = preset_data; 149 | } 150 | 151 | 152 | void CFxPresets::create_bank_dir() 153 | { 154 | if (banks_path == "") 155 | return; 156 | 157 | QDir dr; 158 | dr.setPath (banks_path); 159 | 160 | if (! dr.exists()) 161 | dr.mkpath (banks_path); 162 | } 163 | 164 | 165 | void CFxPresets::bank_selected() 166 | { 167 | QAction *a = qobject_cast(sender()); 168 | QString fname (banks_path); 169 | fname.append ("/").append (a->text()); 170 | 171 | load_bank_file (fname); 172 | } 173 | 174 | 175 | void CFxPresets::update_banks_list (const QString &path) 176 | { 177 | banks_path = path; 178 | 179 | int i = banks_path.lastIndexOf ("/"); 180 | fxname = banks_path.right (banks_path.length() - i - 1); 181 | 182 | qDebug() << "update_banks_list fxname:::::" << fxname; 183 | 184 | QStringList l1 = read_dir_entries (banks_path); 185 | QStringList l2 = read_dir_entries (":/fxpresets" + fxname); 186 | 187 | l1 += l2; 188 | 189 | create_menu_from_list (this, menu_banks, 190 | l1, 191 | SLOT (bank_selected())); 192 | } 193 | -------------------------------------------------------------------------------- /fxpresets.h: -------------------------------------------------------------------------------- 1 | #ifndef FXPRESETS_H 2 | #define FXPRESETS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | class CFxPresets: public QWidget 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | 17 | QMenu *menu; 18 | QMenu *menu_banks; 19 | 20 | QString preset_data; 21 | QString fxname; 22 | 23 | QString banks_path; //path to the plugin's banks 24 | 25 | 26 | QString path_bank; //full path of the current bank 27 | 28 | QMap map; 29 | 30 | QComboBox *cmb_presets; 31 | 32 | 33 | CFxPresets (QWidget *parent = 0); 34 | 35 | void load_bank_file (const QString &fname); 36 | void save_bank_file (const QString &fname); 37 | 38 | void create_bank_dir(); 39 | void update_banks_list (const QString &path); 40 | 41 | signals: 42 | 43 | void preset_changed (const QString &text); 44 | void save_request(); 45 | 46 | 47 | public slots: 48 | 49 | void cmb_presets_currentIndexChanged (const QString &text); 50 | 51 | void bank_new_click(); 52 | void bank_load_click(); 53 | void bank_save_click(); 54 | void bank_save_as_click(); 55 | 56 | void preset_save_as(); 57 | void preset_save(); 58 | 59 | void bank_selected(); 60 | 61 | 62 | }; 63 | 64 | #endif // FXPRESETS_H -------------------------------------------------------------------------------- /fxrack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "gui_utils.h" 10 | #include "fxrack.h" 11 | 12 | CFxList *avail_fx; 13 | 14 | 15 | void CFxRack::tv_activated (const QModelIndex &index) 16 | { 17 | emit fx_activated (index.data().toString()); 18 | 19 | int i = index.row(); 20 | if (i != -1) 21 | effects.at(i)->show_ui(); 22 | } 23 | 24 | /* 25 | void CFxRack::add_entry (AFx *f, bool checked) 26 | { 27 | QStandardItem *item = new QStandardItem (f->name); 28 | item->setCheckable (true); 29 | 30 | if (checked) 31 | item->setCheckState (Qt::Checked); 32 | 33 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled | 34 | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | 35 | Qt::ItemIsDropEnabled); 36 | 37 | model->appendRow (item); 38 | } 39 | */ 40 | 41 | 42 | void CFxRack::add_entry_silent (AFx *f, bool bypass) 43 | { 44 | QStandardItem *item = new QStandardItem (f->modulename); 45 | item->setCheckable (true); 46 | 47 | if (f->bypass) 48 | item->setCheckState (Qt::Unchecked); 49 | else 50 | item->setCheckState (Qt::Checked); 51 | 52 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled | 53 | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | 54 | Qt::ItemIsDropEnabled); 55 | 56 | AFx *tfx = f; 57 | 58 | int i = get_sel_index(); 59 | if (i == -1) 60 | { 61 | model->appendRow (item); 62 | effects.append (tfx); 63 | } 64 | else 65 | { 66 | model->insertRow (i, item); 67 | effects.insert (i, tfx); 68 | } 69 | } 70 | 71 | 72 | void CFxRack::ins_entry (AFx *f) 73 | { 74 | QStandardItem *item = new QStandardItem (f->modulename); 75 | item->setCheckable (true); 76 | item->setCheckState (Qt::Checked); 77 | 78 | item->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEnabled | 79 | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | 80 | Qt::ItemIsDropEnabled); 81 | 82 | AFx *tfx = f;//f->self_create(); 83 | 84 | int i = get_sel_index(); 85 | if (i == -1) 86 | { 87 | model->appendRow (item); 88 | effects.append (tfx); 89 | } 90 | else 91 | { 92 | model->insertRow (i, item); 93 | effects.insert (i, tfx); 94 | } 95 | 96 | tfx->show_ui(); 97 | } 98 | 99 | 100 | void CFxRack::bt_up_clicked() 101 | { 102 | if (! tree_view->selectionModel()->hasSelection()) 103 | return; 104 | 105 | QModelIndex index = tree_view->selectionModel()->currentIndex(); 106 | 107 | int row = index.row(); 108 | if (row == 0) 109 | return; 110 | 111 | QList l = model->takeRow (row); 112 | 113 | int new_row = row - 1; 114 | 115 | model->insertRow (new_row, l[0]); 116 | 117 | effects.swapItemsAt(row, new_row); 118 | } 119 | 120 | 121 | void CFxRack::bt_down_clicked() 122 | { 123 | 124 | if (! tree_view->selectionModel()->hasSelection()) 125 | return; 126 | 127 | QModelIndex index = tree_view->selectionModel()->currentIndex(); 128 | 129 | int row = index.row(); 130 | if (row == model->rowCount() - 1) 131 | return; 132 | 133 | QList l = model->takeRow (row); 134 | 135 | int new_row = row + 1 ; 136 | 137 | model->insertRow (new_row, l[0]); 138 | 139 | effects.swapItemsAt(row, new_row); 140 | } 141 | 142 | 143 | CFxRack::CFxRack (QObject *parent): QObject (parent) 144 | { 145 | avail_fx = new CFxList; 146 | 147 | model = new QStandardItemModel (0, 1, parent); 148 | 149 | connect (model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), 150 | this, SLOT(bypass_dataChanged(QModelIndex,QModelIndex))); 151 | 152 | 153 | tree_view = new CFxTreeView; 154 | tree_view->setHeaderHidden (true); 155 | 156 | tree_view->setRootIsDecorated (false); 157 | tree_view->setModel (model); 158 | 159 | tree_view->setDragEnabled (true); 160 | 161 | //tree_view->header()->setResizeMode (QHeaderView::ResizeToContents); 162 | //tree_view->header()->setStretchLastSection (false); 163 | 164 | tree_view->setSelectionMode (QAbstractItemView::ExtendedSelection); 165 | tree_view->setSelectionBehavior (QAbstractItemView::SelectRows); 166 | 167 | connect (tree_view, SIGNAL(activated(QModelIndex)), this, SLOT(tv_activated(QModelIndex))); 168 | 169 | 170 | inserts = new QWidget; 171 | 172 | inserts->setWindowTitle (tr ("Inserts")); 173 | //inserts->setWindowFlags (Qt::Window | Qt::Tool); 174 | 175 | QVBoxLayout *v_box = new QVBoxLayout; 176 | inserts->setLayout (v_box); 177 | 178 | QPushButton *bt_add = new QPushButton ("+"); 179 | QPushButton *bt_del = new QPushButton ("-"); 180 | 181 | QToolButton *bt_up = new QToolButton; 182 | QToolButton *bt_down = new QToolButton; 183 | bt_up->setArrowType (Qt::UpArrow); 184 | bt_down->setArrowType (Qt::DownArrow); 185 | 186 | connect (bt_up, SIGNAL(clicked()), this, SLOT(bt_up_clicked())); 187 | connect (bt_down, SIGNAL(clicked()), this, SLOT(bt_down_clicked())); 188 | 189 | connect (bt_add, SIGNAL(clicked()), this, SLOT(add_fx())); 190 | connect (bt_del, SIGNAL(clicked()), this, SLOT(del_fx())); 191 | 192 | QHBoxLayout *h_box = new QHBoxLayout; 193 | h_box->addWidget (bt_add); 194 | h_box->addWidget (bt_del); 195 | h_box->addWidget (bt_up); 196 | h_box->addWidget (bt_down); 197 | 198 | v_box->addWidget (tree_view); 199 | v_box->addLayout (h_box); 200 | } 201 | 202 | 203 | void CFxRack::add_fx() 204 | { 205 | CTextListWindow w (tr ("Select"), tr ("Available effects")); 206 | 207 | w.list->addItems (avail_fx->names()); 208 | 209 | int result = w.exec(); 210 | 211 | if (result != QDialog::Accepted) 212 | return; 213 | 214 | AFx *f = avail_fx->find_by_name (w.list->currentItem()->text()); 215 | 216 | ins_entry (f); 217 | 218 | // print_fx_list(); 219 | } 220 | 221 | 222 | void CFxRack::del_fx() 223 | { 224 | int i = get_sel_index(); 225 | if (i == -1) 226 | return; 227 | 228 | QList l = model->takeRow (i); 229 | delete l[0]; 230 | 231 | AFx *f = effects.takeAt (i); 232 | if (f) 233 | delete f; 234 | 235 | print_fx_list(); 236 | } 237 | 238 | 239 | CFxRack::~CFxRack() 240 | { 241 | for (auto *f: effects) 242 | { 243 | f->wnd_ui->close(); 244 | delete f; 245 | } 246 | 247 | //delete avail_fx; 248 | 249 | inserts->close(); 250 | } 251 | 252 | 253 | QString CFxRack::get_sel_fname() 254 | { 255 | if (! tree_view->selectionModel()->hasSelection()) 256 | return QString(); 257 | 258 | QModelIndex index = tree_view->selectionModel()->currentIndex(); 259 | return index.data().toString(); 260 | } 261 | 262 | 263 | const QModelIndex CFxRack::index_from_idx (int idx) 264 | { 265 | QStandardItem *item = model->item (idx); 266 | if (item) 267 | return model->indexFromItem (item); 268 | else 269 | return QModelIndex(); 270 | } 271 | 272 | 273 | int CFxRack::get_sel_index() 274 | { 275 | if (! tree_view->selectionModel()->hasSelection()) 276 | return -1; 277 | 278 | QModelIndex index = tree_view->selectionModel()->currentIndex(); 279 | return index.row(); 280 | } 281 | 282 | 283 | void CFxTreeView::mouseMoveEvent (QMouseEvent *event) 284 | { 285 | /* if (! (event->buttons() & Qt::LeftButton)) 286 | return; 287 | 288 | QStringList l = fman->get_sel_fnames(); 289 | if (l.size() < 1) 290 | return; 291 | 292 | QDrag *drag = new QDrag (this); 293 | QMimeData *mimeData = new QMimeData; 294 | 295 | QList list; 296 | 297 | foreach (QString fn, l) 298 | list.append (QUrl::fromLocalFile (fn)); 299 | 300 | mimeData->setUrls (list); 301 | drag->setMimeData (mimeData); 302 | 303 | if (drag->exec (Qt::CopyAction | 304 | Qt::MoveAction | 305 | Qt::LinkAction) == Qt::MoveAction) 306 | fman->refresh(); 307 | */ 308 | event->accept(); 309 | } 310 | 311 | 312 | void CFxRack::print_fx_list() 313 | { 314 | for (auto *f: effects) 315 | qDebug() << f->modulename; 316 | } 317 | 318 | 319 | void CFxRack::bypass_dataChanged (const QModelIndex & topLeft, const QModelIndex & bottomRight) 320 | { 321 | bool b = model->data (topLeft, Qt::CheckStateRole).toInt(); 322 | 323 | //qDebug() << model->data (topLeft, Qt::DisplayRole).toString() << " = " << b; 324 | //qDebug() << "row = " << topLeft.row(); 325 | 326 | effects[topLeft.row()]->bypass = ! b; 327 | 328 | //if (effects[topLeft.row()]->bypass) 329 | // qDebug() << "bypassed"; 330 | } 331 | 332 | 333 | void CFxRack::bypass_all (bool mode) 334 | { 335 | for (int row = 0; row < model->rowCount(); row++) 336 | { 337 | QStandardItem *si = model->item (row); 338 | if (mode) 339 | si->setCheckState (Qt::Unchecked); 340 | else 341 | si->setCheckState (Qt::Checked); 342 | } 343 | } 344 | 345 | 346 | void CFxRack::set_state_all (FxState state) 347 | { 348 | for (auto *f: effects) 349 | { 350 | f->set_state (state); 351 | } 352 | } 353 | 354 | 355 | void CFxRack::reset_all_fx (size_t srate, size_t ch) 356 | { 357 | for (auto *f: effects) 358 | { 359 | f->reset_params (srate, ch); 360 | } 361 | } 362 | 363 | /* 364 | const QModelIndex CFxRack::index_from_name (const QString &name) 365 | { 366 | QList lst = model->findItems (name); 367 | if (lst.size() > 0) 368 | return model->indexFromItem (lst[0]); 369 | else 370 | return QModelIndex(); 371 | } 372 | */ 373 | -------------------------------------------------------------------------------- /fxrack.h: -------------------------------------------------------------------------------- 1 | #ifndef FXRACK_H 2 | #define FXRACK_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "afx.h" 14 | #include "fxlist.h" 15 | 16 | 17 | class CFxTreeView; 18 | class CFxListInterface; 19 | 20 | 21 | 22 | class CFxRack: public QObject 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | 28 | QList effects; 29 | 30 | QWidget *inserts; //inserts section for the mixer, the "external" widget 31 | CFxTreeView *tree_view; //inside of the inserts widget 32 | 33 | QStandardItemModel *model; 34 | 35 | CFxRack (QObject *parent = 0); 36 | ~CFxRack(); 37 | 38 | // void add_entry (AFx *f, bool checked = true); 39 | void ins_entry (AFx *f); 40 | void add_entry_silent (AFx *f, bool bypass); 41 | 42 | //const QModelIndex index_from_name (const QString &name); 43 | const QModelIndex index_from_idx (int idx); 44 | int get_sel_index(); 45 | 46 | void bypass_all (bool mode = true); 47 | void set_state_all (FxState state); 48 | void reset_all_fx (size_t srate, size_t ch); 49 | 50 | QString get_sel_fname(); 51 | void print_fx_list(); 52 | 53 | public slots: 54 | 55 | void tv_activated (const QModelIndex &index); 56 | void add_fx(); 57 | void del_fx(); 58 | 59 | void bt_up_clicked(); 60 | void bt_down_clicked(); 61 | 62 | void bypass_dataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight); 63 | 64 | signals: 65 | 66 | void fx_activated (const QString &path); 67 | }; 68 | 69 | 70 | class CFxTreeView: public QTreeView 71 | { 72 | Q_OBJECT 73 | 74 | protected: 75 | 76 | void mouseMoveEvent (QMouseEvent *event); 77 | }; 78 | 79 | 80 | #endif // FXRACK_H 81 | -------------------------------------------------------------------------------- /fxset.h: -------------------------------------------------------------------------------- 1 | #ifndef FXSET_H 2 | #define FXSET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "floatbuffer.h" 18 | #include "fx-filter.h" 19 | #include "afx.h" 20 | 21 | 22 | 23 | class CFxSimpleAmp: public AFx 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | 29 | float gain; 30 | 31 | CFxSimpleAmp(); 32 | ~CFxSimpleAmp(); 33 | 34 | QLabel *label; 35 | QDial *dial_gain; 36 | 37 | AFx* self_create(); 38 | 39 | size_t execute (float **input, float **output, size_t frames); 40 | 41 | QString save_params_to_string(); 42 | void load_params_from_string (const QString &s); 43 | 44 | static QString get_modulename() {return QString (tr ("Simple Amp"));}; 45 | static AFx* create_self() {return new CFxSimpleAmp;} 46 | 47 | 48 | public slots: 49 | 50 | void dial_gain_valueChanged (int value); 51 | }; 52 | 53 | 54 | class CFxSimpleOverdrive: public AFx 55 | { 56 | Q_OBJECT 57 | 58 | public: 59 | 60 | float gain; 61 | float level; 62 | 63 | QDial *dial_gain; 64 | QDial *dial_level; 65 | 66 | CFxSimpleOverdrive(); 67 | ~CFxSimpleOverdrive(); 68 | 69 | AFx* self_create(); 70 | 71 | size_t execute (float **input, float **output, size_t frames); 72 | 73 | QString save_params_to_string(); 74 | void load_params_from_string (const QString &s); 75 | 76 | static QString get_modulename() {return QString (tr ("Simple Overdrive"));}; 77 | static AFx* create_self() {return new CFxSimpleOverdrive;} 78 | 79 | public slots: 80 | 81 | void dial_gain_valueChanged (int value); 82 | void dial_level_valueChanged (int value); 83 | }; 84 | 85 | 86 | class CFxDelay: public AFx 87 | { 88 | Q_OBJECT 89 | 90 | public: 91 | 92 | QLabel *label; 93 | 94 | CFloatBuffer *fb; 95 | 96 | QDoubleSpinBox *spb_mixlevel; 97 | QDoubleSpinBox *spb_time; 98 | 99 | float mixlevel; 100 | float delay_msecs; 101 | 102 | CFxDelay(); 103 | ~CFxDelay(); 104 | 105 | AFx* self_create(); 106 | 107 | size_t execute (float **input, float **output, size_t frames); 108 | void reset_params (size_t srate, size_t ch); 109 | 110 | QString save_params_to_string(); 111 | void load_params_from_string (const QString &s); 112 | 113 | static QString get_modulename() {return QString (tr ("Simple delay"));}; 114 | static AFx* create_self() {return new CFxDelay;} 115 | 116 | public slots: 117 | 118 | void spb_mixlevel_changed (double value); 119 | void spb_time_changed (double value); 120 | }; 121 | 122 | 123 | class CFxSimpleFilter: public AFx 124 | { 125 | Q_OBJECT 126 | 127 | public: 128 | 129 | QDoubleSpinBox *dsb_cutoff_freq; 130 | QDoubleSpinBox *dsb_reso; 131 | QComboBox *cmb_filter_mode; 132 | 133 | CFilter filter; 134 | 135 | CFxSimpleFilter(); 136 | 137 | QString save_params_to_string(); 138 | void load_params_from_string (const QString &s); 139 | 140 | static QString get_modulename() {return QString (tr ("Simple Filter"));}; 141 | static AFx* create_self() {return new CFxSimpleFilter;} 142 | 143 | AFx* self_create(); 144 | 145 | 146 | size_t execute (float **input, float **output, size_t frames); 147 | void reset_params (size_t srate, size_t ch); 148 | 149 | public slots: 150 | 151 | void cmb_filter_mode_currentIndexChanged (int index); 152 | void dsb_cutoff_valueChanged (double d); 153 | void dsb_reso_valueChanged (double d); 154 | }; 155 | 156 | 157 | class CFxMetaluga: public AFx 158 | { 159 | Q_OBJECT 160 | 161 | public: 162 | 163 | CFilter filter; 164 | 165 | float gain; 166 | float drive; 167 | float tone; 168 | float level; 169 | 170 | QDial *dial_gain; 171 | QDial *dial_drive; 172 | QDial *dial_tone; 173 | QDial *dial_level; 174 | 175 | CFxMetaluga(); 176 | ~CFxMetaluga(); 177 | 178 | AFx* self_create(); 179 | 180 | static QString get_modulename() {return QString (tr ("Metaluga (overdrive/dist pedal)"));}; 181 | static AFx* create_self() {return new CFxMetaluga;} 182 | 183 | QString save_params_to_string(); 184 | void load_params_from_string (const QString &s); 185 | 186 | 187 | 188 | size_t execute (float **input, float **output, size_t frames); 189 | void reset_params (size_t srate, size_t ch); 190 | 191 | public slots: 192 | 193 | void dial_gain_valueChanged (int value); 194 | void dial_drive_valueChanged (int value); 195 | void dial_tone_valueChanged (int value); 196 | void dial_level_valueChanged (int value); 197 | }; 198 | 199 | 200 | class CFxJest: public AFx 201 | { 202 | Q_OBJECT 203 | 204 | public: 205 | 206 | CFilter filter; 207 | 208 | float gain; 209 | float drive; 210 | float tone; 211 | float level; 212 | 213 | QDial *dial_gain; 214 | QDial *dial_drive; 215 | QDial *dial_tone; 216 | QDial *dial_level; 217 | 218 | CFxJest(); 219 | 220 | QString save_params_to_string(); 221 | void load_params_from_string (const QString &s); 222 | 223 | AFx* self_create(); 224 | 225 | static QString get_modulename() {return QString (tr ("Jest' (overdrive/dist)"));}; 226 | static AFx* create_self() {return new CFxJest;} 227 | 228 | 229 | size_t execute (float **input, float **output, size_t frames); 230 | void reset_params (size_t srate, size_t ch); 231 | 232 | public slots: 233 | 234 | void dial_gain_valueChanged (int value); 235 | void dial_drive_valueChanged (int value); 236 | void dial_tone_valueChanged (int value); 237 | void dial_level_valueChanged (int value); 238 | }; 239 | 240 | 241 | class CFxVynil: public AFx 242 | { 243 | Q_OBJECT 244 | 245 | public: 246 | 247 | 248 | QDial *dial_scratches_amount; 249 | QDoubleSpinBox *spb_mixlevel; 250 | 251 | float mixlevel; 252 | float cutoff; 253 | 254 | CFxVynil(); 255 | 256 | QString save_params_to_string(); 257 | void load_params_from_string (const QString &s); 258 | 259 | static QString get_modulename() {return QString (tr ("Vynil Taste"));}; 260 | static AFx* create_self() {return new CFxVynil;} 261 | 262 | AFx* self_create(); 263 | 264 | size_t execute (float **input, float **output, size_t frames); 265 | void reset_params (size_t srate, size_t ch); 266 | 267 | public slots: 268 | 269 | void dial_scratches_amount_valueChanged (int value); 270 | void spb_mixlevel_changed (double value); 271 | }; 272 | 273 | 274 | #endif // FXSET_H 275 | -------------------------------------------------------------------------------- /gui_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | this code is Public Domain 3 | */ 4 | 5 | 6 | #include "gui_utils.h" 7 | #include "utils.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | void create_menu_from_list (QObject *handler, 15 | QMenu *menu, 16 | const QStringList &list, 17 | const char *method 18 | ) 19 | { 20 | menu->setTearOffEnabled (true); 21 | 22 | for (const auto &s: list) 23 | { 24 | if (! s.startsWith("#")) 25 | { 26 | QAction *act = new QAction (s, menu->parentWidget()); 27 | act->setData (s); 28 | handler->connect (act, SIGNAL(triggered()), handler, method); 29 | menu->addAction (act); 30 | } 31 | } 32 | } 33 | 34 | 35 | void create_menu_from_dir (QObject *handler, 36 | QMenu *menu, 37 | const QString &dir, 38 | const char *method 39 | ) 40 | { 41 | menu->setTearOffEnabled (true); 42 | QDir d (dir); 43 | QFileInfoList lst_fi = d.entryInfoList (QDir::NoDotAndDotDot | QDir::AllEntries, 44 | QDir::DirsFirst | QDir::IgnoreCase | 45 | QDir::LocaleAware | QDir::Name); 46 | 47 | for (const auto &fi: lst_fi) 48 | 49 | //foreach (QFileInfo fi, lst_fi) 50 | { 51 | if (fi.isDir()) 52 | { 53 | QMenu *mni_temp = menu->addMenu (fi.fileName()); 54 | create_menu_from_dir (handler, mni_temp, 55 | fi.filePath(), method); 56 | } 57 | else 58 | { 59 | QAction *act = new QAction (fi.fileName(), menu->parentWidget()); 60 | act->setData (fi.filePath()); 61 | handler->connect (act, SIGNAL(triggered()), handler, method); 62 | menu->addAction (act); 63 | } 64 | } 65 | } 66 | 67 | //uses dir name as menuitem, no recursion 68 | void create_menu_from_dir_dir (QObject *handler, 69 | QMenu *menu, 70 | const QString &dir, 71 | const char *method 72 | ) 73 | { 74 | menu->setTearOffEnabled (true); 75 | QDir d (dir); 76 | QFileInfoList lst_fi = d.entryInfoList (QDir::NoDotAndDotDot | QDir::Dirs, 77 | QDir::IgnoreCase | QDir::LocaleAware | QDir::Name); 78 | 79 | for (const auto &fi: lst_fi) 80 | { 81 | if (fi.isDir()) 82 | { 83 | QAction *act = new QAction (fi.fileName(), menu->parentWidget()); 84 | act->setData (fi.filePath()); 85 | handler->connect (act, SIGNAL(triggered()), handler, method); 86 | menu->addAction (act); 87 | } 88 | } 89 | } 90 | 91 | QLineEdit* new_line_edit (QBoxLayout *layout, const QString &label, const QString &def_value) 92 | { 93 | QHBoxLayout *lt_h = new QHBoxLayout; 94 | QLabel *l = new QLabel (label); 95 | 96 | QLineEdit *r = new QLineEdit; 97 | r->setText (def_value); 98 | 99 | lt_h->addWidget (l); 100 | lt_h ->addWidget (r); 101 | 102 | layout->addLayout (lt_h); 103 | 104 | return r; 105 | } 106 | 107 | 108 | QSpinBox* new_spin_box (QBoxLayout *layout, const QString &label, int min, int max, int value, int step) 109 | { 110 | QHBoxLayout *lt_h = new QHBoxLayout; 111 | QLabel *l = new QLabel (label); 112 | 113 | QSpinBox *r = new QSpinBox; 114 | 115 | r->setSingleStep (step); 116 | r->setRange (min, max); 117 | r->setValue (value); 118 | 119 | lt_h->addWidget (l); 120 | lt_h ->addWidget (r); 121 | 122 | layout->addLayout (lt_h); 123 | 124 | return r; 125 | } 126 | 127 | 128 | QComboBox* new_combobox (QBoxLayout *layout, 129 | const QString &label, 130 | const QStringList &items, 131 | const QString &def_value) 132 | { 133 | QHBoxLayout *lt_h = new QHBoxLayout; 134 | QLabel *l = new QLabel (label); 135 | 136 | QComboBox *r = new QComboBox; 137 | 138 | r->addItems (items); 139 | r->setCurrentIndex (r->findText (def_value)); 140 | 141 | lt_h->addWidget (l); 142 | lt_h->addWidget (r); 143 | 144 | layout->addLayout (lt_h); 145 | 146 | return r; 147 | } 148 | 149 | 150 | CTextListWindow::CTextListWindow (const QString &title, const QString &label_text): QDialog (0) 151 | { 152 | //setAttribute (Qt::WA_DeleteOnClose); 153 | QVBoxLayout *lt = new QVBoxLayout; 154 | 155 | QLabel *l = new QLabel (label_text); 156 | 157 | list = new QListWidget (this); 158 | 159 | lt->addWidget (l); 160 | lt->addWidget (list); 161 | 162 | QHBoxLayout *lt_h = new QHBoxLayout; 163 | 164 | QPushButton *bt_apply = new QPushButton (tr ("OK")); 165 | QPushButton *bt_exit = new QPushButton (tr ("Exit")); 166 | 167 | connect (list, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(accept())); 168 | 169 | 170 | connect (bt_apply, SIGNAL(clicked()), this, SLOT(accept())); 171 | connect (bt_exit, SIGNAL(clicked()), this, SLOT(reject())); 172 | 173 | lt_h->addWidget (bt_apply); 174 | lt_h->addWidget (bt_exit); 175 | 176 | lt->addLayout (lt_h); 177 | 178 | setLayout (lt); 179 | 180 | setWindowTitle (title); 181 | } 182 | 183 | 184 | double input_double_value (const QString &caption, const QString &lbl, 185 | double minval, double maxval, double defval, double step) 186 | { 187 | double result = 0; 188 | 189 | QDialog wnd; 190 | 191 | wnd.setWindowTitle (caption); 192 | 193 | QVBoxLayout *v_box = new QVBoxLayout; 194 | wnd.setLayout (v_box); 195 | 196 | QLabel *label = new QLabel (lbl); 197 | 198 | QLineEdit ed; 199 | 200 | v_box->addWidget (&ed); 201 | v_box->addWidget (label); 202 | 203 | QHBoxLayout *lt_h = new QHBoxLayout; 204 | 205 | QPushButton *bt_apply = new QPushButton ("OK"); 206 | QPushButton *bt_exit = new QPushButton ("Cancel"); 207 | 208 | wnd.connect (bt_exit, SIGNAL(clicked()), &wnd, SLOT(reject())); 209 | wnd.connect (bt_apply, SIGNAL(clicked()), &wnd, SLOT(accept())); 210 | 211 | lt_h->addWidget (bt_apply); 212 | lt_h->addWidget (bt_exit); 213 | 214 | v_box->addLayout (lt_h); 215 | 216 | if (wnd.exec()) 217 | //result = spb_d->value(); 218 | result = ed.text().toDouble(); 219 | 220 | return result; 221 | } 222 | 223 | 224 | QAction* menu_add_item (QObject *obj, 225 | QMenu *menu, 226 | const QString &caption, 227 | const char *method, 228 | const QString &shortkt, 229 | const QString &iconpath 230 | ) 231 | { 232 | QAction *act = new QAction (caption, obj); 233 | 234 | if (! shortkt.isEmpty()) 235 | act->setShortcut (shortkt); 236 | 237 | if (! iconpath.isEmpty()) 238 | act->setIcon (QIcon (iconpath)); 239 | 240 | obj->connect (act, SIGNAL(triggered()), obj, method); 241 | menu->addAction (act); 242 | return act; 243 | } 244 | -------------------------------------------------------------------------------- /gui_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef GUI_UTILS_H 2 | #define GUI_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | class CTextListWindow: public QDialog 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | 20 | QListWidget *list; 21 | CTextListWindow (const QString &title, const QString &label_text); 22 | }; 23 | 24 | 25 | QAction* menu_add_item (QObject *obj, 26 | QMenu *menu, 27 | const QString &caption, 28 | const char *method, 29 | const QString &shortkt = "", 30 | const QString &iconpath = "" 31 | ); 32 | 33 | void create_menu_from_list (QObject *handler, 34 | QMenu *menu, 35 | const QStringList &list, 36 | const char *method 37 | ); 38 | 39 | 40 | void create_menu_from_dir (QObject *handler, 41 | QMenu *menu, 42 | const QString &dir, 43 | const char *method 44 | ); 45 | 46 | void create_menu_from_dir_dir (QObject *handler, 47 | QMenu *menu, 48 | const QString &dir, 49 | const char *method 50 | ); 51 | 52 | 53 | QLineEdit* new_line_edit (QBoxLayout *layout, const QString &label, const QString &def_value); 54 | QSpinBox* new_spin_box (QBoxLayout *layout, const QString &label, int min, int max, int value, int step = 1); 55 | 56 | double input_double_value (const QString &caption, const QString &lbl, 57 | double minval, double maxval, double defval, double step); 58 | 59 | QComboBox* new_combobox (QBoxLayout *layout, 60 | const QString &label, 61 | const QStringList &items, 62 | const QString &def_value); 63 | 64 | 65 | #endif // GUI_UTILS_H 66 | -------------------------------------------------------------------------------- /icons/create-dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/create-dir.png -------------------------------------------------------------------------------- /icons/current-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/current-list.png -------------------------------------------------------------------------------- /icons/edit-copy-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/edit-copy-active.png -------------------------------------------------------------------------------- /icons/edit-copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/edit-copy.png -------------------------------------------------------------------------------- /icons/edit-cut-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/edit-cut-active.png -------------------------------------------------------------------------------- /icons/edit-cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/edit-cut.png -------------------------------------------------------------------------------- /icons/edit-paste-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/edit-paste-active.png -------------------------------------------------------------------------------- /icons/edit-paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/edit-paste.png -------------------------------------------------------------------------------- /icons/eko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/eko.png -------------------------------------------------------------------------------- /icons/file-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/file-new.png -------------------------------------------------------------------------------- /icons/file-open-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/file-open-active.png -------------------------------------------------------------------------------- /icons/file-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/file-open.png -------------------------------------------------------------------------------- /icons/file-save-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/file-save-active.png -------------------------------------------------------------------------------- /icons/file-save-as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/file-save-as.png -------------------------------------------------------------------------------- /icons/file-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/file-save.png -------------------------------------------------------------------------------- /icons/go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/go.png -------------------------------------------------------------------------------- /icons/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/home.png -------------------------------------------------------------------------------- /icons/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/pause.png -------------------------------------------------------------------------------- /icons/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/play.png -------------------------------------------------------------------------------- /icons/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/refresh.png -------------------------------------------------------------------------------- /icons/search_find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/search_find.png -------------------------------------------------------------------------------- /icons/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/icons/stop.png -------------------------------------------------------------------------------- /libretta_interpolator.cpp: -------------------------------------------------------------------------------- 1 | #include "libretta_interpolator.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | CFloatInterpolator::CFloatInterpolator (size_t x_1, float y_1, size_t x_2, float y_2) 8 | { 9 | y1 = y_1; 10 | y2 = y_2; 11 | 12 | x1 = x_1; 13 | x2 = x_2; 14 | } 15 | 16 | 17 | CFloatInterpolatorSimple::CFloatInterpolatorSimple (size_t x_1, float y_1, size_t x_2, float y_2): 18 | CFloatInterpolator (x_1, y_1, x_2, y_2) 19 | { 20 | size_t elements_between = x_2 - x_1; 21 | 22 | //cout << "y1: " << y1 << endl; 23 | //cout << "y2: " << y2 << endl; 24 | 25 | if (y2 > y1) 26 | { 27 | values_diff = y2 - y1; 28 | 29 | if (values_diff == 0) 30 | part = 0.0f; 31 | else 32 | part = (float) values_diff / elements_between; 33 | 34 | } 35 | else 36 | { 37 | float values_diff = y1 - y2; 38 | 39 | if (values_diff == 0) 40 | part = 0; 41 | else 42 | part = (float) values_diff / elements_between; 43 | } 44 | } 45 | 46 | 47 | float CFloatInterpolatorSimple::get_y_at_x (size_t x) 48 | { 49 | if (y2 > y1) 50 | { 51 | return (y1 + ((x - x1) * part)); 52 | 53 | } 54 | else 55 | return (y1 - ((x - x1) * part)); 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /libretta_interpolator.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBRETTA_INTERPOLATOR_H 2 | #define LIBRETTA_INTERPOLATOR_H 3 | 4 | using namespace std; 5 | 6 | #include 7 | 8 | class CFloatInterpolator 9 | { 10 | public: 11 | 12 | float y1; 13 | float y2; 14 | 15 | size_t x1; 16 | size_t x2; 17 | 18 | CFloatInterpolator (size_t x_1, float y_1, size_t x_2, float y_2); 19 | virtual ~CFloatInterpolator() {}; 20 | 21 | virtual float get_y_at_x (size_t x) = 0; 22 | 23 | }; 24 | 25 | class CFloatInterpolatorSimple: public CFloatInterpolator 26 | { 27 | public: 28 | 29 | float values_diff; 30 | float part; 31 | 32 | CFloatInterpolatorSimple (size_t x_1, float y_1, size_t x_2, float y_2); 33 | 34 | float get_y_at_x (size_t x); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /logmemo.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2007-2011 by Peter Semiletov * 3 | * peter.semiletov@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 3 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 | ***************************************************************************/ 20 | 21 | 22 | #include "logmemo.h" 23 | 24 | #include 25 | #include 26 | 27 | 28 | CLogMemo::CLogMemo (QPlainTextEdit *m) 29 | { 30 | memo = m; 31 | setObjectName ("logmemo"); 32 | memo->setFocusPolicy (Qt::ClickFocus); 33 | memo->setUndoRedoEnabled (false); 34 | memo->setReadOnly (true); 35 | } 36 | 37 | 38 | void CLogMemo::log (const QString &text) 39 | { 40 | QTextCursor cr = memo->textCursor(); 41 | cr.movePosition (QTextCursor::Start); 42 | cr.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, 0); 43 | memo->setTextCursor (cr); 44 | 45 | QTime t = QTime::currentTime(); 46 | 47 | memo->textCursor().insertHtml ("[" + t.toString("hh:mm:ss") + "] " + text + "
"); 48 | 49 | cr = memo->textCursor(); 50 | cr.movePosition (QTextCursor::Start); 51 | cr.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, 0); 52 | memo->setTextCursor (cr); 53 | } 54 | -------------------------------------------------------------------------------- /logmemo.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2007-2010 by Peter Semiletov * 3 | * peter.semiletov@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 3 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 | ***************************************************************************/ 20 | 21 | #ifndef LOGMEMO_H 22 | #define LOGMEMO_H 23 | 24 | //#include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | class CLogMemo: public QObject 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | 37 | QPlainTextEdit *memo; 38 | CLogMemo (QPlainTextEdit *m); 39 | 40 | public slots: 41 | 42 | void log (const QString &text); 43 | }; 44 | 45 | #endif // LOGMEMO_H 46 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyleft 2007-2015 by Peter Semiletov * 3 | * tea@list.ru * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 3 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 | ***************************************************************************/ 20 | 21 | 22 | #include 23 | #include "eko.h" 24 | 25 | int main (int argc, char *argv[]) 26 | { 27 | Q_INIT_RESOURCE (eko); 28 | qApp->setApplicationName ("EKO"); 29 | 30 | CApplication app (argc, argv); 31 | CEKO mw; 32 | 33 | mw.show(); 34 | 35 | return app.exec(); 36 | } 37 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('eko', ['cpp','c'], 2 | default_options : ['cpp_std=c++11'], 3 | version : '7.0.1', 4 | license : 'GPLv3') 5 | 6 | add_global_arguments('-DVERSION_NUMBER="7.0.1"', language : 'cpp') 7 | add_global_arguments('-DUSE_QML_STUFF=1', language : 'cpp') 8 | 9 | #harcoded for now 10 | moc_params = ['-DQT_VERSION=0x050000', '-DUSE_QML_STUFF=1'] 11 | 12 | if build_machine.system() == 'linux' 13 | moc_params += ['-DQ_OS_LINUX=1', '-DQ_OS_UNIX=1'] 14 | endif 15 | 16 | compiler = meson.get_compiler('cpp') 17 | 18 | sndfile_dep = compiler.find_library('sndfile', required : true) 19 | samplerate_dep = compiler.find_library('samplerate', required : true) 20 | portaudio_dep = compiler.find_library('portaudio', required : true) 21 | 22 | qt5_dep = dependency('qt5', modules : ['Core', 'Gui', 'Widgets']) 23 | qt5 = import('qt5') 24 | 25 | 26 | eko_headers_moc = [ 27 | 'eko.h', 28 | 'document.h', 29 | 'utils.h', 30 | 'fman.h', 31 | 'shortcuts.h', 32 | 'logmemo.h', 33 | 'tio.h', 34 | 'fxset.h', 35 | 'gui_utils.h', 36 | 'libretta_interpolator.h', 37 | 'floatbuffer.h', 38 | 'envelope.h', 39 | 'fx-filter.h', 40 | 'fx-panners.h', 41 | 'cvlevelmeter.h', 42 | 'fxrack.h', 43 | 'afx.h', 44 | 'fxlist.h', 45 | 'noisegen.h', 46 | 'db.h', 47 | 'fxpresets.h'] 48 | 49 | 50 | src_processed = qt5.preprocess( 51 | moc_headers : eko_headers_moc, 52 | moc_extra_arguments: moc_params, 53 | qresources : 'eko.qrc') 54 | 55 | 56 | eko_source = ['main.cpp', 57 | 'eko.cpp', 58 | 'main.cpp', 59 | 'document.cpp', 60 | 'utils.cpp', 61 | 'fman.cpp', 62 | 'shortcuts.cpp', 63 | 'logmemo.cpp', 64 | 'tio.cpp', 65 | 'fxset.cpp', 66 | 'gui_utils.cpp', 67 | 'libretta_interpolator.cpp', 68 | 'floatbuffer.cpp', 69 | 'envelope.cpp', 70 | 'fx-filter.cpp', 71 | 'fx-panners.cpp', 72 | 'cvlevelmeter.cpp', 73 | 'fxrack.cpp', 74 | 'afx.cpp', 75 | 'fxlist.cpp', 76 | 'noisegen.cpp', 77 | 'db.cpp', 78 | 'fxpresets.cpp'] 79 | 80 | 81 | eko_exe = executable ('eko', 82 | sources : [src_processed, eko_source], 83 | install : true, 84 | dependencies : [qt5_dep, sndfile_dep, portaudio_dep, samplerate_dep] 85 | ) 86 | 87 | 88 | install_data(['icons/eko.png'], 89 | install_dir : 'share/icons/hicolor/64x64/apps') 90 | 91 | install_data(['desktop/eko.desktop'], 92 | install_dir : 'share/applications') 93 | -------------------------------------------------------------------------------- /noisegen.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GPL'ed code from Audacity 3 | Noise.cpp 4 | by Dominic Mazzoni 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "noisegen.h" 13 | 14 | 15 | float* noise_generate_white (size_t len, float amp) //gen one channel noise 16 | { 17 | float *buffer = new float [len]; 18 | 19 | std::random_device rd; 20 | std::default_random_engine gen (rd()); 21 | std::uniform_real_distribution<> dis(-1.0, 1.0); 22 | 23 | for (size_t i = 0; i < len; i++) 24 | { 25 | buffer[i] = (float)dis(gen) * amp; 26 | } 27 | 28 | return buffer; 29 | } 30 | 31 | /* 32 | Following the 33 | http://www.firstpr.com.au/dsp/pink-noise/ 34 | Using the Paul Kellet's filtering 35 | */ 36 | 37 | float* noise_generate_pink (size_t len, float amp) //gen one channel noise 38 | { 39 | float *buffer = new float [len]; 40 | 41 | float b0, b1, b2; 42 | 43 | std::random_device rd; 44 | std::knuth_b gen (rd()); 45 | std::uniform_real_distribution<> dis(-1.0, 1.0); 46 | 47 | for (size_t i = 0; i < len; i++) 48 | { 49 | float white = (float)dis(gen); 50 | 51 | b0 = 0.99765 * b0 + white * 0.0990460; 52 | b1 = 0.96300 * b1 + white * 0.2965164; 53 | b2 = 0.57000 * b2 + white * 1.0526913; 54 | float tmp = (b0 + b1 + b2 + white * 0.1848) / 4; 55 | 56 | buffer[i] = tmp * amp; 57 | } 58 | 59 | return buffer; 60 | } 61 | 62 | //Using the Paul Kellet's filtering 63 | float* noise_generate_pink2 (size_t len, float amp) //gen one channel noise 64 | { 65 | float *buffer = new float [len]; 66 | 67 | float b0, b1, b2, b3, b4, b5, b6; 68 | b6 = 0; 69 | 70 | std::random_device rd; 71 | std::knuth_b gen (rd()); 72 | std::uniform_real_distribution<> dis(-1.0, 1.0); 73 | 74 | for (size_t i = 0; i < len; i++) 75 | { 76 | float white = (float)dis(gen); 77 | 78 | b0 = 0.99886 * b0 + white * 0.0555179; 79 | b1 = 0.99332 * b1 + white * 0.0750759; 80 | b2 = 0.96900 * b2 + white * 0.1538520; 81 | b3 = 0.86650 * b3 + white * 0.3104856; 82 | b4 = 0.55000 * b4 + white * 0.5329522; 83 | b5 = -0.7616 * b5 - white * 0.0168980; 84 | float pink = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; 85 | b6 = white * 0.115926; 86 | 87 | buffer[i] = pink * amp / 7; 88 | } 89 | 90 | return buffer; 91 | } 92 | 93 | 94 | //brown B[n] = (B[n-1] + C * w[n]) / (1. + C) 95 | -------------------------------------------------------------------------------- /noisegen.h: -------------------------------------------------------------------------------- 1 | #ifndef NOISEGEN_H 2 | #define NOISEGEN_H 3 | 4 | #include 5 | 6 | 7 | float* noise_generate_white (size_t len, float amp); //gen one channel noise 8 | float* noise_generate_pink (size_t len, float amp); //gen one channel noise 9 | float* noise_generate_pink2 (size_t len, float amp); //gen one channel noise 10 | 11 | 12 | #endif // NOISEGEN_H 13 | -------------------------------------------------------------------------------- /palettes/EKO: -------------------------------------------------------------------------------- 1 | waveform_background=white 2 | waveform_foreground=darkMagenta 3 | waveform_selection_foreground=#004c00 4 | waveform_selection_alpha=127 5 | axis=black 6 | cursor=red 7 | text=black 8 | envelope=red 9 | timeruler.background_color=#dcdcdc 10 | timeruler.foreground=black 11 | env_point_selected=#ff2ba3 -------------------------------------------------------------------------------- /palettes/Grey: -------------------------------------------------------------------------------- 1 | waveform_background=#808080 2 | waveform_foreground=#7c1480 3 | waveform_selection_foreground=#ff8000 4 | waveform_selection_alpha=127 5 | axis=black 6 | cursor=red 7 | text=black 8 | timeruler.background_color=#585858 9 | timeruler.foreground=white 10 | -------------------------------------------------------------------------------- /palettes/Spring: -------------------------------------------------------------------------------- 1 | waveform_background=#578049 2 | waveform_foreground=black 3 | waveform_selection_foreground=#ffff00 4 | waveform_selection_alpha=127 5 | axis=black 6 | cursor=red 7 | text=#eeff99 8 | timeruler.background_color=#7cc096 9 | timeruler.foreground=black 10 | -------------------------------------------------------------------------------- /palettes/Vinyl: -------------------------------------------------------------------------------- 1 | waveform_background=#1e1814 2 | waveform_foreground=#ffea9e 3 | waveform_selection_foreground=#006000 4 | waveform_selection_alpha=127 5 | axis=red 6 | cursor=#3ef9ff 7 | text=red 8 | timeruler.background_color=#a3b3bc 9 | timeruler.foreground=black -------------------------------------------------------------------------------- /palettes/Winter: -------------------------------------------------------------------------------- 1 | waveform_background=#004040 2 | waveform_foreground=white 3 | waveform_selection_foreground=#00c0c0 4 | waveform_selection_alpha=127 5 | axis=#070db3 6 | cursor=red 7 | text=#9cedff 8 | timeruler.background_color=#c0c0ff 9 | timeruler.foreground=black 10 | draw_shadow=1 11 | shadow_color=#303030 -------------------------------------------------------------------------------- /shortcuts.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 2007-2016 by Peter Semiletov * 3 | * tea@list.ru * 4 | 5 | this code is Public Domain 6 | 7 | ***************************************************************************/ 8 | 9 | 10 | #include "shortcuts.h" 11 | #include "utils.h" 12 | #include "gui_utils.h" 13 | 14 | #include 15 | #include 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | 25 | 26 | QString mod_to_string (Qt::KeyboardModifiers k) 27 | { 28 | QString s; 29 | 30 | if (k & Qt::ShiftModifier) 31 | s += "Shift+"; 32 | 33 | if (k & Qt::ControlModifier) 34 | s += "Ctrl+"; 35 | 36 | if (k & Qt::AltModifier) 37 | s += "Alt+"; 38 | 39 | if (k & Qt::MetaModifier) 40 | s+= "Meta+"; 41 | 42 | return s; 43 | } 44 | 45 | 46 | QString keycode_to_string (int k) 47 | { 48 | // return QKeySequence(k).toString(); 49 | 50 | QString s; 51 | 52 | switch (k) 53 | { 54 | case Qt::Key_F1: 55 | s = "F1"; 56 | break; 57 | 58 | case Qt::Key_F2: 59 | s = "F2"; 60 | break; 61 | 62 | case Qt::Key_F3: 63 | s = "F3"; 64 | break; 65 | 66 | case Qt::Key_F4: 67 | s = "F4"; 68 | break; 69 | 70 | case Qt::Key_F5: 71 | s = "F5"; 72 | break; 73 | 74 | case Qt::Key_F6: 75 | s = "F6"; 76 | break; 77 | 78 | case Qt::Key_F7: 79 | s = "F7"; 80 | break; 81 | 82 | case Qt::Key_F8: 83 | s = "F8"; 84 | break; 85 | 86 | case Qt::Key_F9: 87 | s = "F9"; 88 | break; 89 | 90 | case Qt::Key_F10: 91 | s = "F10"; 92 | break; 93 | 94 | case Qt::Key_F11: 95 | s = "F11"; 96 | break; 97 | 98 | case Qt::Key_F12: 99 | s = "F12"; 100 | break; 101 | 102 | default: 103 | s = QChar (k); 104 | } 105 | 106 | return s; 107 | } 108 | 109 | 110 | 111 | CShortcuts::CShortcuts (QWidget *widget) 112 | { 113 | w = widget; 114 | } 115 | 116 | 117 | //FIXME: 118 | void CShortcuts::captions_iterate() 119 | { 120 | captions.clear(); 121 | QList a = w->findChildren (); 122 | 123 | for (auto *ac: a) 124 | if (ac) 125 | if (! ac->text().isEmpty()) 126 | { 127 | captions.prepend (ac->text()); 128 | // qDebug() << ac->text(); 129 | } 130 | 131 | captions.sort(); 132 | captions.removeDuplicates(); //nasty hack 133 | } 134 | 135 | 136 | QAction* CShortcuts::find_by_caption (const QString &text) 137 | { 138 | QList a = w->findChildren(); 139 | 140 | for (auto *ac: a) 141 | if (ac->text() == text) 142 | return ac; 143 | 144 | return NULL; 145 | } 146 | 147 | 148 | QAction* CShortcuts::find_by_shortcut (const QString &shcut) 149 | { 150 | QList a = w->findChildren(); 151 | 152 | for (auto *ac: a) 153 | if (ac->shortcut().toString() == shcut) 154 | return ac; 155 | 156 | return NULL; 157 | } 158 | 159 | 160 | QKeySequence CShortcuts::find_seq_by_caption (const QString &text) 161 | { 162 | QAction *a = find_by_caption (text); 163 | 164 | if (a) 165 | return a->shortcut(); 166 | 167 | return QKeySequence::fromString ("Ctrl+Alt+Z"); 168 | } 169 | 170 | 171 | void CShortcuts::set_new_shortcut (const QString &menuitem, const QString &shcut) 172 | { 173 | QAction *b = find_by_shortcut (shcut); 174 | if (b) 175 | b->setShortcut (QKeySequence("")); 176 | 177 | QAction *a = find_by_caption (menuitem); 178 | if (a) 179 | a->setShortcut (QKeySequence (shcut)); 180 | } 181 | 182 | 183 | void CShortcuts::save_to_file (const QString &file_name) 184 | { 185 | QList a = w->findChildren(); 186 | QString s; 187 | 188 | for (auto *ac: a) 189 | if (! ac->shortcut().toString().isEmpty()) 190 | s.append (ac->text()).append ("=").append (ac->shortcut().toString()).append ("\n"); 191 | 192 | qstring_save (file_name, s); 193 | } 194 | 195 | 196 | void CShortcuts::load_from_file (const QString &file_name) 197 | { 198 | if (! file_exists (file_name)) 199 | return; 200 | 201 | QHash hash = hash_load_keyval (file_name); 202 | 203 | QList a = w->findChildren(); 204 | 205 | for (auto *ac: a) 206 | if (hash.contains (ac->text())) 207 | ac->setShortcut (QKeySequence (hash.value (ac->text()))); 208 | } 209 | 210 | 211 | void CShortcutEntry::keyPressEvent (QKeyEvent *event) 212 | { 213 | event->accept(); 214 | QString text = mod_to_string (event->modifiers()) + keycode_to_string (event->key()); 215 | setText (text); 216 | qDebug() << text; 217 | } 218 | -------------------------------------------------------------------------------- /shortcuts.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 2007-2016 by Peter Semiletov * 3 | * tea@list.ru * 4 | 5 | this code is Public Domain 6 | 7 | ***************************************************************************/ 8 | 9 | #ifndef SHORTCUTS_H 10 | #define SHORTCUTS_H 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | class CShortcutEntry: public QLineEdit 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | 24 | void keyPressEvent (QKeyEvent *event); 25 | }; 26 | 27 | 28 | class CShortcuts: public QObject 29 | { 30 | Q_OBJECT 31 | 32 | public: 33 | 34 | QWidget *w; 35 | QString fname; 36 | QHash hash; 37 | QStringList captions; 38 | 39 | CShortcuts (QWidget *widget); 40 | void captions_iterate(); 41 | QAction* find_by_caption (const QString &text); 42 | QAction* find_by_shortcut (const QString &shcut); 43 | 44 | QKeySequence find_seq_by_caption (const QString &text); 45 | void set_new_shortcut (const QString &menuitem, const QString &shcut); 46 | 47 | void save_to_file (const QString &file_name); 48 | void load_from_file (const QString &file_name); 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /themes/Cotton/stylesheet.css: -------------------------------------------------------------------------------- 1 | QWidget 2 | { 3 | background-color: #2f2d55; 4 | color: white; 5 | } 6 | 7 | 8 | QLineEdit { 9 | border: 2px solid gray; 10 | border-radius: 8px; 11 | background-color: #00557f; 12 | color: white; 13 | selection-background-color: darkgray; 14 | } 15 | 16 | /* 17 | QComboBox#FIF{ 18 | border-radius: 8px; 19 | } 20 | */ 21 | 22 | QPlainTextEdit 23 | { 24 | border-radius: 15px; 25 | } 26 | 27 | 28 | QMenu 29 | { 30 | background-color: #2d436d; 31 | border: 1px solid grey; 32 | } 33 | 34 | QMenu::item { 35 | background-color: transparent; 36 | } 37 | 38 | QMenu::item:selected { 39 | background-color: #3e7dbc; 40 | } 41 | 42 | 43 | QTreeView 44 | { 45 | background-color: #3b4a7f; 46 | alternate-background-color: #3b4a7f; 47 | } 48 | 49 | QListView 50 | { 51 | background-color: #3b4a7f; 52 | alternate-background-color: #3b4a7f; 53 | } 54 | 55 | 56 | QScrollBar:vertical { 57 | width: 24px; 58 | border: 1px solid grey; 59 | 60 | } 61 | 62 | 63 | 64 | QTabWidget::pane{ 65 | border: 0px; 66 | /*background-repeat: no repeat; */ 67 | } 68 | 69 | 70 | QTabWidget::tab-bar#tab_widget{ 71 | alignment: center; 72 | 73 | } 74 | 75 | 76 | /* 77 | QScrollBar::handle:vertical { 78 | border: 1px solid grey; 79 | background: #639469; 80 | min-width: 24px; 81 | min-height: 8px; 82 | subcontrol-origin: margin; 83 | }*/ 84 | 85 | /* 86 | QPushButton { 87 | 88 | background-color: qlineargradient(spread:pad, x1:0.538048, y1:1, x2:0.498, y2:0.0113636, stop:0 rgba(0, 62, 0, 255), stop:0.681275 rgba(0, 116, 65, 255)); 89 | border: 1px; border-radius: 5px; 90 | 91 | 92 | } 93 | */ 94 | /*QPushButton:hover:!pressed { color: black; }*/ -------------------------------------------------------------------------------- /themes/Plum/stylesheet.css: -------------------------------------------------------------------------------- 1 | QWidget 2 | { 3 | background-color: #9a656c; 4 | color: white; 5 | } 6 | 7 | 8 | QLineEdit { 9 | border: 1px solid gray; 10 | border-radius: 6px; 11 | background-color: #704349; 12 | color: white; 13 | selection-background-color: darkgray; 14 | } 15 | 16 | /* 17 | QComboBox#FIF{ 18 | border-radius: 8px; 19 | } 20 | */ 21 | 22 | QPlainTextEdit 23 | { 24 | border-radius: 15px; 25 | } 26 | 27 | 28 | QMenu 29 | { 30 | background-color: #8c727d; 31 | border: 1px solid grey; 32 | } 33 | 34 | QMenu::item { 35 | background-color: transparent; 36 | } 37 | 38 | QMenu::item:selected { 39 | background-color: #613c41; 40 | } 41 | 42 | 43 | QTreeView 44 | { 45 | alternate-background-color: #4f6384; 46 | } 47 | 48 | 49 | QListView 50 | { 51 | alternate-background-color: #4f6384; 52 | } 53 | 54 | 55 | QScrollBar:vertical { 56 | width: 24px; 57 | border: 1px solid grey; 58 | 59 | } 60 | 61 | 62 | 63 | QTabWidget::pane{ 64 | border: 0px; 65 | /*background-repeat: no repeat; */ 66 | } 67 | 68 | 69 | QTabWidget::tab-bar#tab_widget{ 70 | alignment: center; 71 | 72 | } 73 | 74 | 75 | /* 76 | QScrollBar::handle:vertical { 77 | border: 1px solid grey; 78 | background: #639469; 79 | min-width: 24px; 80 | min-height: 8px; 81 | subcontrol-origin: margin; 82 | }*/ 83 | 84 | /* 85 | QPushButton { 86 | 87 | background-color: qlineargradient(spread:pad, x1:0.538048, y1:1, x2:0.498, y2:0.0113636, stop:0 rgba(0, 62, 0, 255), stop:0.681275 rgba(0, 116, 65, 255)); 88 | border: 1px; border-radius: 5px; 89 | 90 | 91 | } 92 | */ 93 | /*QPushButton:hover:!pressed { color: black; }*/ -------------------------------------------------------------------------------- /themes/Smaragd/stylesheet.css: -------------------------------------------------------------------------------- 1 | QWidget 2 | { 3 | background-color: #0d553f; color: white; 4 | } 5 | 6 | QLineEdit 7 | { 8 | border: 1px solid black; 9 | border-radius: 3px; 10 | background-color: #005300; 11 | color: white; 12 | selection-background-color: darkgray; 13 | } 14 | 15 | /*QComboBox#FIF{ border-radius: 8px; }*/ 16 | 17 | QPlainTextEdit 18 | { 19 | border-radius: 3px; 20 | } 21 | 22 | QMenu 23 | { 24 | background-color: #33684f; 25 | border: 1px solid black; 26 | } 27 | 28 | QMenu::item 29 | { 30 | background-color: transparent; 31 | } 32 | 33 | QMenu::item:selected { 34 | background-color: #87a787; 35 | color: black; 36 | } 37 | 38 | QTreeView 39 | { 40 | alternate-background-color: #2d5e5e; 41 | } 42 | 43 | QScrollBar:vertical 44 | { 45 | width: 24px; 46 | border: 1px solid grey; 47 | } 48 | 49 | QTabWidget::pane 50 | { border: 0px;} 51 | 52 | /*QTabWidget::tab-bar#tab_widget{ alignment: center;}*/ -------------------------------------------------------------------------------- /themes/TEA/stylesheet.css: -------------------------------------------------------------------------------- 1 | QTabWidget::pane#tab_widget { 2 | border-top: 0px solid grey; 3 | background-color: grey; 4 | } -------------------------------------------------------------------------------- /themes/Turbo/stylesheet.css: -------------------------------------------------------------------------------- 1 | QWidget 2 | { 3 | background-color: #babbd4; 4 | color: black; 5 | } 6 | 7 | 8 | QLineEdit { 9 | border: 2px solid gray; 10 | padding: 0 2px; 11 | background-color: #1818b2; 12 | color: white; 13 | selection-background-color: darkgray; 14 | } 15 | 16 | QMenuBar 17 | { 18 | background-color: #b2b2b2; 19 | } 20 | 21 | 22 | QMenu 23 | { 24 | margin: 16px; 25 | background-color: #b2b2b2; 26 | border: 1px solid black; 27 | } 28 | 29 | QMenu::item { 30 | background-color: transparent; 31 | } 32 | 33 | QMenu::item:selected { 34 | background-color: #18b218; 35 | } 36 | 37 | 38 | QTreeView 39 | { 40 | alternate-background-color: #18b2b2; 41 | background-color: #18b2b2; 42 | selection-color: white; 43 | selection-background-color: #18b218; 44 | } 45 | 46 | 47 | QListView 48 | { 49 | alternate-background-color: #18b2b2; 50 | background-color: #18b2b2; 51 | selection-color: white; 52 | selection-background-color: #18b218; 53 | 54 | } 55 | 56 | QScrollBar:vertical { 57 | width: 24px; 58 | border: 1px solid grey; 59 | } 60 | 61 | 62 | QPushButton 63 | { 64 | border-width: 1px; 65 | color: black; 66 | background-color: #159d15; 67 | border-color: black; 68 | border-top: 4px solid black; 69 | border-right: 4px solid black; 70 | min-width: 24px; 71 | } 72 | 73 | 74 | QPushButton:pressed 75 | { 76 | border-width: 1px; 77 | color: black; 78 | background-color: #159d15; 79 | border-color: black; 80 | border-top: 1px solid black; 81 | min-width: 24px; 82 | } 83 | 84 | 85 | QTabBar::tab { 86 | background: #b2b2b2; 87 | border-top: 1px solid black; 88 | border-left: 1px solid black; 89 | border-right: 1px solid black; 90 | border-bottom: 0px; 91 | padding: 4px; 92 | color: grey; 93 | } 94 | 95 | QTabBar::tab:selected { 96 | background: #b2b2b2; 97 | border-top: 1px solid black; 98 | border-left: 1px solid black; 99 | border-right: 1px solid black; 100 | border-bottom: 0px; 101 | padding: 4px; 102 | color: yellow; 103 | } 104 | 105 | /* 106 | QTabBar::tab:!selected { 107 | margin-top: 1px; 108 | border-bottom: 0px; 109 | } 110 | */ -------------------------------------------------------------------------------- /themes/Vegan/stylesheet.css: -------------------------------------------------------------------------------- 1 | QWidget 2 | { 3 | background-color: #5d8168; 4 | color: white; 5 | } 6 | 7 | 8 | QLineEdit { 9 | border: 2px solid gray; 10 | border-radius: 8px; 11 | background-color: #3a4d38; 12 | color: white; 13 | selection-background-color: darkgray; 14 | } 15 | 16 | /* 17 | QComboBox#FIF{ 18 | border-radius: 8px; 19 | } 20 | */ 21 | 22 | QPlainTextEdit 23 | { 24 | border-radius: 15px; 25 | } 26 | 27 | 28 | QMenu 29 | { 30 | background-color: #436a61; 31 | border: 1px solid grey; 32 | } 33 | 34 | QMenu::item { 35 | background-color: transparent; 36 | } 37 | 38 | QMenu::item:selected { 39 | background-color: #639469; 40 | } 41 | 42 | 43 | QTreeView 44 | { 45 | alternate-background-color: #5f915b; 46 | } 47 | 48 | 49 | QScrollBar:vertical { 50 | width: 24px; 51 | border: 1px solid grey; 52 | 53 | } 54 | 55 | 56 | 57 | QTabWidget::pane{ 58 | border: 0px; 59 | /*background-repeat: no repeat; */ 60 | } 61 | 62 | 63 | QTabWidget::tab-bar#tab_widget{ 64 | alignment: center; 65 | 66 | } 67 | 68 | 69 | /* 70 | QScrollBar::handle:vertical { 71 | border: 1px solid grey; 72 | background: #639469; 73 | min-width: 24px; 74 | min-height: 8px; 75 | subcontrol-origin: margin; 76 | }*/ 77 | 78 | /* 79 | QPushButton { 80 | 81 | background-color: qlineargradient(spread:pad, x1:0.538048, y1:1, x2:0.498, y2:0.0113636, stop:0 rgba(0, 62, 0, 255), stop:0.681275 rgba(0, 116, 65, 255)); 82 | border: 1px; border-radius: 5px; 83 | 84 | 85 | } 86 | */ 87 | /*QPushButton:hover:!pressed { color: black; }*/ -------------------------------------------------------------------------------- /tio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | //#include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tio.h" 13 | #include "utils.h" 14 | 15 | 16 | using namespace std; 17 | 18 | 19 | int proxy_video_decoder; 20 | double ogg_q; 21 | CFileFormats *file_formats; 22 | QString temp_mp3_fname; 23 | 24 | 25 | float* load_whole_sample (const char *fname, SF_INFO &sf) 26 | { 27 | SNDFILE *file = sf_open (fname, SFM_READ, &sf); 28 | 29 | if (! file) 30 | return NULL; 31 | 32 | if (sf.channels == 0 || sf.frames == 0) 33 | return NULL; 34 | 35 | float *buffer = new float [sf.channels * sf.frames]; 36 | sf_count_t zzz = sf_readf_float (file, buffer, sf.frames); 37 | sf_close (file); 38 | 39 | return buffer; 40 | } 41 | 42 | 43 | CTioPlainAudio::~CTioPlainAudio() 44 | { 45 | // if (data) 46 | // free (data); 47 | } 48 | 49 | 50 | CFloatBuffer* CTioPlainAudio::load (const QString &fname) 51 | { 52 | SF_INFO sf; 53 | sf.format = 0; 54 | 55 | SNDFILE *file = sf_open (fname.toUtf8().data(), SFM_READ, &sf); 56 | 57 | if (! file) 58 | return NULL; 59 | 60 | if (sf.channels == 0 || sf.frames == 0) 61 | return NULL; 62 | 63 | float *filebuf = new float [sf.channels * sf.frames]; 64 | sf_count_t zzz = sf_readf_float (file, filebuf, sf.frames); 65 | sf_close (file); 66 | 67 | CFloatBuffer *fb = 0; 68 | 69 | // if (sf.channels == 1) 70 | // fb = new CFloatBuffer (filebuf, sf.frames); 71 | // else 72 | 73 | fb = new CFloatBuffer (filebuf, sf.frames, sf.channels); 74 | 75 | /* 76 | if (sf.channels != 1) //because we did the copy in the constructor 77 | delete [] filebuf; 78 | */ 79 | fb->samplerate = sf.samplerate; 80 | fb->sndfile_format = sf.format; 81 | 82 | return fb; 83 | } 84 | 85 | 86 | bool CTioPlainAudio::save (const QString &fname) 87 | { 88 | if (! float_input_buffer) 89 | { 90 | qDebug() << "! data"; 91 | return false; 92 | } 93 | 94 | SF_INFO sf; 95 | 96 | sf.samplerate = float_input_buffer->samplerate; 97 | sf.channels = float_input_buffer->channels; 98 | sf.format = float_input_buffer->sndfile_format; 99 | 100 | if (! sf_format_check (&sf)) 101 | { 102 | qDebug() << "! sf_format_check (&sf)"; 103 | return false; 104 | } 105 | 106 | //if pcm 16 bit 107 | if ((sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_16) 108 | return save_16bit_pcm (fname); 109 | 110 | SNDFILE *hfile = sf_open (fname.toUtf8().data(), SFM_WRITE, &sf); 111 | 112 | double quality = ogg_q; 113 | sf_command (hfile, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof (quality)) ; 114 | 115 | if (float_input_buffer->channels == 1) 116 | { 117 | sf_writef_float (hfile, float_input_buffer->buffer[0], float_input_buffer->length_frames); 118 | } 119 | else 120 | { 121 | float *interleavedbuf = float_input_buffer->to_interleaved(); 122 | sf_writef_float (hfile, interleavedbuf, float_input_buffer->length_frames); 123 | delete [] interleavedbuf; 124 | } 125 | 126 | 127 | sf_close (hfile); 128 | 129 | return true; 130 | } 131 | 132 | 133 | CTioHandler::CTioHandler() 134 | { 135 | list.append (new CTioPlainAudio); 136 | list.append (new CTioProxy); 137 | 138 | CTio *instance; 139 | 140 | for (int i = 0; i < list.size(); i++) 141 | { 142 | instance = list.at (i); 143 | supported_extensions += instance->extensions; 144 | } 145 | } 146 | 147 | 148 | CTioHandler::~CTioHandler() 149 | { 150 | while (! list.isEmpty()) 151 | delete list.takeFirst(); 152 | } 153 | 154 | 155 | bool CTioHandler::is_ext_supported (const QString &fname) 156 | { 157 | QString ext = file_get_ext (fname).toLower(); 158 | 159 | if (supported_extensions.indexOf (ext) != -1) 160 | return true; 161 | 162 | return false; 163 | } 164 | 165 | 166 | CTio* CTioHandler::get_for_fname (const QString &fname) 167 | { 168 | CTio *instance; 169 | QString ext = file_get_ext (fname).toLower(); 170 | 171 | for (int i = 0; i < list.size(); i++) 172 | { 173 | instance = list.at (i); 174 | 175 | if (instance->extensions.indexOf (ext) != -1) 176 | return instance; 177 | } 178 | 179 | return NULL; 180 | } 181 | 182 | 183 | CTioPlainAudio::CTioPlainAudio() 184 | { 185 | id = "CTioPlainAudio"; 186 | ronly = false; 187 | extensions += file_formats->hextensions.values(); 188 | } 189 | 190 | 191 | CTioPlainAudio::CTioPlainAudio (bool rnly) 192 | { 193 | ronly = rnly; 194 | float_input_buffer = 0; 195 | } 196 | 197 | 198 | bool CTioReadOnly::save (const QString &fname) 199 | { 200 | error_string = tr ("saving of this format is not supported"); 201 | return false; 202 | } 203 | 204 | 205 | CFileFormats::CFileFormats() 206 | { 207 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_PCM_U8); 208 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_PCM_16); 209 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_PCM_24); 210 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_PCM_32); 211 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_FLOAT); 212 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_DOUBLE); 213 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_ULAW); 214 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_ALAW); 215 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_IMA_ADPCM); 216 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_MS_ADPCM); 217 | hformat.insert (SF_FORMAT_WAV, SF_FORMAT_GSM610); 218 | 219 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_PCM_U8); 220 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_PCM_16); 221 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_PCM_24); 222 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_PCM_32); 223 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_FLOAT); 224 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_DOUBLE); 225 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_ULAW); 226 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_ALAW); 227 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_IMA_ADPCM); 228 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_MS_ADPCM); 229 | hformat.insert (SF_FORMAT_WAVEX, SF_FORMAT_GSM610); 230 | 231 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_PCM_S8); 232 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_PCM_16); 233 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_PCM_24); 234 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_PCM_32); 235 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_PCM_U8); 236 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_FLOAT); 237 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_DOUBLE); 238 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_PCM_S8); 239 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_ULAW); 240 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_ALAW); 241 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_GSM610); 242 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_DWVW_12); 243 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_DWVW_16); 244 | hformat.insert (SF_FORMAT_AIFF, SF_FORMAT_DWVW_24); 245 | 246 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_PCM_S8); 247 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_PCM_16); 248 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_PCM_24); 249 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_PCM_32); 250 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_FLOAT); 251 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_DOUBLE); 252 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_ULAW); 253 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_ALAW); 254 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_G721_32); 255 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_G723_24); 256 | hformat.insert (SF_FORMAT_AU, SF_FORMAT_G723_40); 257 | 258 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_PCM_S8); 259 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_PCM_16); 260 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_PCM_24); 261 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_PCM_32); 262 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_PCM_U8); 263 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_FLOAT); 264 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_DOUBLE); 265 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_ULAW); 266 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_ALAW); 267 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_GSM610); 268 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_DWVW_12); 269 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_DWVW_16); 270 | hformat.insert (SF_FORMAT_RAW, SF_FORMAT_DWVW_24); 271 | 272 | hformat.insert (SF_FORMAT_PAF, SF_FORMAT_PCM_S8); 273 | hformat.insert (SF_FORMAT_PAF, SF_FORMAT_PCM_16); 274 | hformat.insert (SF_FORMAT_PAF, SF_FORMAT_PCM_24); 275 | 276 | hformat.insert (SF_FORMAT_SVX, SF_FORMAT_PCM_S8); 277 | hformat.insert (SF_FORMAT_SVX, SF_FORMAT_PCM_16); 278 | 279 | hformat.insert (SF_FORMAT_NIST, SF_FORMAT_PCM_S8); 280 | hformat.insert (SF_FORMAT_NIST, SF_FORMAT_PCM_16); 281 | hformat.insert (SF_FORMAT_NIST, SF_FORMAT_PCM_24); 282 | hformat.insert (SF_FORMAT_NIST, SF_FORMAT_PCM_32); 283 | hformat.insert (SF_FORMAT_NIST, SF_FORMAT_ULAW); 284 | hformat.insert (SF_FORMAT_NIST, SF_FORMAT_ALAW); 285 | 286 | hformat.insert (SF_FORMAT_IRCAM, SF_FORMAT_PCM_16); 287 | hformat.insert (SF_FORMAT_IRCAM, SF_FORMAT_PCM_24); 288 | hformat.insert (SF_FORMAT_IRCAM, SF_FORMAT_PCM_32); 289 | hformat.insert (SF_FORMAT_IRCAM, SF_FORMAT_FLOAT); 290 | hformat.insert (SF_FORMAT_IRCAM, SF_FORMAT_ULAW); 291 | hformat.insert (SF_FORMAT_IRCAM, SF_FORMAT_ALAW); 292 | 293 | hformat.insert (SF_FORMAT_VOC, SF_FORMAT_PCM_U8); 294 | hformat.insert (SF_FORMAT_VOC, SF_FORMAT_PCM_16); 295 | hformat.insert (SF_FORMAT_VOC, SF_FORMAT_ULAW); 296 | hformat.insert (SF_FORMAT_VOC, SF_FORMAT_ALAW); 297 | 298 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_PCM_U8); 299 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_PCM_16); 300 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_PCM_24); 301 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_PCM_32); 302 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_FLOAT); 303 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_DOUBLE); 304 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_ALAW); 305 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_ULAW); 306 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_IMA_ADPCM); 307 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_MS_ADPCM); 308 | hformat.insert (SF_FORMAT_W64, SF_FORMAT_GSM610); 309 | 310 | hformat.insert (SF_FORMAT_MAT4, SF_FORMAT_PCM_16); 311 | hformat.insert (SF_FORMAT_MAT4, SF_FORMAT_PCM_32); 312 | hformat.insert (SF_FORMAT_MAT4, SF_FORMAT_FLOAT); 313 | hformat.insert (SF_FORMAT_MAT4, SF_FORMAT_DOUBLE); 314 | 315 | hformat.insert (SF_FORMAT_MAT5, SF_FORMAT_PCM_U8); 316 | hformat.insert (SF_FORMAT_MAT5, SF_FORMAT_PCM_16); 317 | hformat.insert (SF_FORMAT_MAT5, SF_FORMAT_PCM_32); 318 | hformat.insert (SF_FORMAT_MAT5, SF_FORMAT_FLOAT); 319 | hformat.insert (SF_FORMAT_MAT5, SF_FORMAT_DOUBLE); 320 | 321 | hformat.insert (SF_FORMAT_PVF, SF_FORMAT_PCM_S8); 322 | hformat.insert (SF_FORMAT_PVF, SF_FORMAT_PCM_16); 323 | hformat.insert (SF_FORMAT_PVF, SF_FORMAT_PCM_32); 324 | 325 | hformat.insert (SF_FORMAT_XI, SF_FORMAT_DPCM_8); 326 | hformat.insert (SF_FORMAT_XI, SF_FORMAT_DPCM_16); 327 | 328 | hformat.insert (SF_FORMAT_HTK, SF_FORMAT_PCM_16); 329 | 330 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_PCM_S8); 331 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_PCM_16); 332 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_PCM_24); 333 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_PCM_32); 334 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_FLOAT); 335 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_DOUBLE); 336 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_ULAW); 337 | hformat.insert (SF_FORMAT_CAF, SF_FORMAT_ALAW); 338 | 339 | hformat.insert (SF_FORMAT_SD2, SF_FORMAT_PCM_S8); 340 | hformat.insert (SF_FORMAT_SD2, SF_FORMAT_PCM_16); 341 | hformat.insert (SF_FORMAT_SD2, SF_FORMAT_PCM_24); 342 | 343 | hformat.insert (SF_FORMAT_FLAC, SF_FORMAT_PCM_S8); 344 | hformat.insert (SF_FORMAT_FLAC, SF_FORMAT_PCM_16); 345 | hformat.insert (SF_FORMAT_FLAC, SF_FORMAT_PCM_24); 346 | hformat.insert (SF_FORMAT_OGG, SF_FORMAT_VORBIS); 347 | 348 | hformatnames.insert (SF_FORMAT_WAV, "Microsoft WAV format (little endian)"); 349 | hformatnames.insert (SF_FORMAT_AIFF, "Apple/SGI AIFF format (big endian)"); 350 | hformatnames.insert (SF_FORMAT_AU, "Sun/NeXT AU format (big endian)"); 351 | hformatnames.insert (SF_FORMAT_RAW, "RAW PCM data"); 352 | hformatnames.insert (SF_FORMAT_PAF, "Ensoniq PARIS file format"); 353 | hformatnames.insert (SF_FORMAT_SVX, "Amiga IFF / SVX8 / SV16 format"); 354 | hformatnames.insert (SF_FORMAT_NIST, "Sphere NIST format"); 355 | hformatnames.insert (SF_FORMAT_VOC, "VOC files"); 356 | hformatnames.insert (SF_FORMAT_IRCAM, "Berkeley/IRCAM/CARL"); 357 | hformatnames.insert (SF_FORMAT_W64, "Sonic Foundry's 64 bit RIFF/WAV"); 358 | hformatnames.insert (SF_FORMAT_MAT4, "Matlab (tm) V4.2 / GNU Octave 2.0"); 359 | hformatnames.insert (SF_FORMAT_MAT5, "Matlab (tm) V5.0 / GNU Octave 2.1"); 360 | hformatnames.insert (SF_FORMAT_PVF, "Portable Voice Format"); 361 | hformatnames.insert (SF_FORMAT_XI, "Fasttracker 2 Extended Instrument"); 362 | hformatnames.insert (SF_FORMAT_HTK, "HMM Tool Kit format"); 363 | hformatnames.insert (SF_FORMAT_SDS, "Midi Sample Dump Standard"); 364 | hformatnames.insert (SF_FORMAT_AVR, "Audio Visual Research"); 365 | hformatnames.insert (SF_FORMAT_WAVEX, "MS WAVE with WAVEFORMATEX"); 366 | hformatnames.insert (SF_FORMAT_SD2, "Sound Designer 2"); 367 | hformatnames.insert (SF_FORMAT_FLAC, "FLAC lossless file format"); 368 | hformatnames.insert (SF_FORMAT_CAF, "Core Audio File format"); 369 | hformatnames.insert (SF_FORMAT_OGG, "Xiph OGG container"); 370 | 371 | 372 | hextensions.insert (SF_FORMAT_WAV, "wav"); 373 | hextensions.insert (SF_FORMAT_AIFF, "aiff"); 374 | hextensions.insert (SF_FORMAT_AIFF, "aif"); 375 | hextensions.insert (SF_FORMAT_AU, "au"); 376 | hextensions.insert (SF_FORMAT_RAW, "raw"); 377 | hextensions.insert (SF_FORMAT_PAF, "paf"); 378 | hextensions.insert (SF_FORMAT_SVX, "iff"); 379 | hextensions.insert (SF_FORMAT_NIST, "Sphere NIST format");//ext? 380 | hextensions.insert (SF_FORMAT_VOC, "voc"); 381 | hextensions.insert (SF_FORMAT_IRCAM, "sf"); //not sound font 382 | hextensions.insert (SF_FORMAT_W64, "wav"); 383 | hextensions.insert (SF_FORMAT_MAT4, "mat"); 384 | hextensions.insert (SF_FORMAT_MAT5, "mat"); 385 | hextensions.insert (SF_FORMAT_PVF, "pvf"); 386 | hextensions.insert (SF_FORMAT_XI, "xi"); 387 | hextensions.insert (SF_FORMAT_HTK, "htk"); 388 | hextensions.insert (SF_FORMAT_SDS, "sds"); 389 | hextensions.insert (SF_FORMAT_AVR, "avr"); 390 | hextensions.insert (SF_FORMAT_WAVEX, "wav"); //see http://msdn.microsoft.com/en-us/library/dd757720%28VS.85%29.aspx 391 | hextensions.insert (SF_FORMAT_SD2, "sd2"); 392 | hextensions.insert (SF_FORMAT_FLAC, "flac"); 393 | hextensions.insert (SF_FORMAT_CAF, "caf"); 394 | hextensions.insert (SF_FORMAT_OGG, "ogg"); 395 | 396 | 397 | hsubtype.insert (SF_FORMAT_PCM_S8, "Signed 8 bit data"); 398 | hsubtype.insert (SF_FORMAT_PCM_16, "Signed 16 bit data"); 399 | hsubtype.insert (SF_FORMAT_PCM_24, "Signed 24 bit data"); 400 | hsubtype.insert (SF_FORMAT_PCM_32, "Signed 32 bit data"); 401 | hsubtype.insert (SF_FORMAT_PCM_U8, "Unsigned 8 bit data (WAV and RAW only)"); 402 | hsubtype.insert (SF_FORMAT_FLOAT, "32 bit float data"); 403 | hsubtype.insert (SF_FORMAT_DOUBLE, "64 bit float data"); 404 | hsubtype.insert (SF_FORMAT_ULAW, "U-Law encoded"); 405 | hsubtype.insert (SF_FORMAT_ALAW, "A-Law encoded"); 406 | hsubtype.insert (SF_FORMAT_IMA_ADPCM, "IMA ADPCM"); 407 | hsubtype.insert (SF_FORMAT_MS_ADPCM, "Microsoft ADPCM"); 408 | hsubtype.insert (SF_FORMAT_GSM610, "GSM 6.10 encoding"); 409 | hsubtype.insert (SF_FORMAT_VOX_ADPCM, "Oki Dialogic ADPCM encoding"); 410 | hsubtype.insert (SF_FORMAT_G721_32, "32kbs G721 ADPCM encoding"); 411 | hsubtype.insert (SF_FORMAT_G723_24, "24kbs G723 ADPCM encoding"); 412 | hsubtype.insert (SF_FORMAT_G723_40, "40kbs G723 ADPCM encoding"); 413 | hsubtype.insert (SF_FORMAT_DWVW_12, "12 bit Delta Width Variable Word encoding"); 414 | hsubtype.insert (SF_FORMAT_DWVW_16, "16 bit Delta Width Variable Word encoding"); 415 | hsubtype.insert (SF_FORMAT_DWVW_24, "24 bit Delta Width Variable Word encoding"); 416 | hsubtype.insert (SF_FORMAT_DWVW_N, "N bit Delta Width Variable Word encoding"); 417 | hsubtype.insert (SF_FORMAT_DPCM_8, "8 bit differential PCM (XI only)"); 418 | hsubtype.insert (SF_FORMAT_DPCM_16, "16 bit differential PCM (XI only)"); 419 | hsubtype.insert (SF_FORMAT_VORBIS, "Xiph Vorbis encoding"); 420 | } 421 | 422 | 423 | void file_formats_init() 424 | { 425 | file_formats = new CFileFormats; 426 | } 427 | 428 | 429 | void file_formats_done() 430 | { 431 | delete file_formats; 432 | } 433 | 434 | 435 | bool CTioPlainAudio::save_16bit_pcm (const QString &fname) 436 | { 437 | if (! float_input_buffer) 438 | { 439 | qDebug() << "! data"; 440 | return false; 441 | } 442 | 443 | SF_INFO sf; 444 | 445 | sf.samplerate = float_input_buffer->samplerate; 446 | sf.channels = float_input_buffer->channels; 447 | sf.format = SF_FORMAT_WAV; 448 | sf.format |= SF_FORMAT_PCM_16; 449 | 450 | if (! sf_format_check (&sf)) 451 | { 452 | qDebug() << "! sf_format_check (&sf)"; 453 | return false; 454 | } 455 | 456 | // qDebug() << "CTioPlainAudio::save_16bit_pcm"; 457 | 458 | //correctly convert data to 16-bit array 459 | 460 | size_t buflen = float_input_buffer->length_frames * sf.channels; 461 | 462 | float *flbuf; 463 | 464 | if (float_input_buffer->channels == 1) 465 | flbuf = float_input_buffer->buffer[0]; 466 | else 467 | flbuf = float_input_buffer->to_interleaved(); 468 | 469 | short int *buf = new short int [buflen]; 470 | 471 | for (size_t i = 0; i < buflen; i++) 472 | { 473 | float f = flbuf[i]; 474 | 475 | if (f >= 1.0) 476 | buf[i] = f * 32767; 477 | else 478 | buf[i] = f * 32768; 479 | } 480 | 481 | SNDFILE *file = sf_open (fname.toUtf8(), SFM_WRITE, &sf); 482 | 483 | sf_writef_short (file, buf, float_input_buffer->length_frames); 484 | 485 | sf_close (file); 486 | 487 | delete [] buf; 488 | 489 | if (float_input_buffer->channels > 1) 490 | delete [] flbuf; 491 | 492 | return true; 493 | } 494 | 495 | 496 | CTioProxy::CTioProxy() 497 | { 498 | ronly = true; 499 | id = "CTioProxy"; 500 | 501 | QString exts_videos = "mp3,avi,mp4,mpeg2,flv,mkv,aac,vob,wmv,3gp,3ga,m2t,mov,mpeg,h264,ts,webm,asf,wma,ogm,wv,wvc,rm,qt,nut,smi,ac3,divx,dv,fli,flc,cpk"; 502 | QStringList lexts_videos = exts_videos.split (","); 503 | for (const auto &ext: lexts_videos) 504 | { 505 | extensions += ext; 506 | } 507 | } 508 | 509 | 510 | CTioProxy::~CTioProxy() 511 | { 512 | } 513 | 514 | 515 | CFloatBuffer* CTioProxy::load (const QString &fname) 516 | { 517 | QString command = "ffmpeg -y -nostats -i \"@FILEIN\" -acodec pcm_f32le -ac 2 \"@FILEOUT\""; 518 | 519 | command = command.replace ("@FILEIN", fname); 520 | command = command.replace ("@FILEOUT", temp_mp3_fname); 521 | 522 | QApplication::setOverrideCursor (QCursor(Qt::WaitCursor)); 523 | 524 | int exit_code = system (command.toUtf8().data()); 525 | 526 | /* QProcess *process = new QProcess; 527 | 528 | 529 | #if QT_VERSION >= 0x060000 530 | process->startCommand (command); 531 | #else 532 | process->startCommand (command); 533 | #endif 534 | */ 535 | /* 536 | QProcess ffmpeg; 537 | ffmpeg.start("ffmpeg" , QStringList() 538 | << "-y" 539 | << "-nostats" 540 | << "-i" << "\"" << fname << "\"" 541 | << "-acodec" << "pcm_f32le" 542 | << "-ac" << "2" 543 | << "\"" << temp_mp3_fname << "\""); 544 | 545 | ffmpeg.waitForFinished(-1); 546 | */ 547 | // qDebug() << "exit_code" << exit_code; 548 | 549 | QApplication::restoreOverrideCursor(); 550 | 551 | if (exit_code < 0) 552 | return 0; 553 | 554 | if (file_exists (temp_mp3_fname)) 555 | { 556 | CTioPlainAudio *pa = new CTioPlainAudio (true); 557 | CFloatBuffer *fb = pa->load (temp_mp3_fname); 558 | delete pa; 559 | return fb; 560 | } 561 | 562 | return 0; 563 | } 564 | 565 | 566 | bool CTioProxy::save (const QString &fname) 567 | { 568 | error_string = tr ("saving of this format is not supported"); 569 | return false; 570 | } 571 | 572 | 573 | bool CTioProxy::save_16bit_pcm (const QString &fname) 574 | { 575 | error_string = tr ("saving of this format is not supported"); 576 | return false; 577 | } 578 | -------------------------------------------------------------------------------- /tio.h: -------------------------------------------------------------------------------- 1 | #ifndef TIO_H 2 | #define TIO_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "floatbuffer.h" 12 | 13 | 14 | class CFileFormats 15 | { 16 | public: 17 | 18 | QMultiHash hformat; 19 | QHash hsubtype; 20 | QHash hformatnames; 21 | QMultiHash hextensions; 22 | 23 | CFileFormats(); 24 | }; 25 | 26 | 27 | class CSignaturesList: public QObject 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | QString encname; 33 | QList words; 34 | }; 35 | 36 | 37 | class CTio: public QObject 38 | { 39 | Q_OBJECT 40 | 41 | public: 42 | 43 | QString id; 44 | 45 | bool ronly; 46 | 47 | CFloatBuffer *float_input_buffer; 48 | QStringList extensions; 49 | QString error_string; 50 | 51 | virtual CFloatBuffer* load (const QString &fname) = 0; 52 | virtual bool save (const QString &fname) = 0; 53 | virtual bool save_16bit_pcm (const QString &fname) = 0; 54 | }; 55 | 56 | 57 | class CTioPlainAudio: public CTio 58 | { 59 | Q_OBJECT 60 | 61 | public: 62 | 63 | CTioPlainAudio(); 64 | CTioPlainAudio (bool rnly); 65 | 66 | ~CTioPlainAudio(); 67 | CFloatBuffer* load (const QString &fname); 68 | bool save (const QString &fname); 69 | bool save_16bit_pcm (const QString &fname); 70 | }; 71 | 72 | 73 | class CTioProxy: public CTio 74 | { 75 | Q_OBJECT 76 | 77 | public: 78 | 79 | QHash proxies; 80 | 81 | CTioProxy(); 82 | ~CTioProxy(); 83 | CFloatBuffer* load (const QString &fname); 84 | bool save (const QString &fname); 85 | bool save_16bit_pcm (const QString &fname); 86 | }; 87 | 88 | 89 | 90 | class CTioReadOnly: public CTio 91 | { 92 | Q_OBJECT 93 | 94 | public: 95 | 96 | bool save (const QString &fname); 97 | }; 98 | 99 | 100 | class CTioHandler: public QObject 101 | { 102 | Q_OBJECT 103 | 104 | public: 105 | 106 | QList list; 107 | 108 | QStringList supported_extensions; 109 | 110 | CTioHandler(); 111 | ~CTioHandler(); 112 | 113 | bool is_ext_supported (const QString &fname); 114 | 115 | CTio* get_for_fname (const QString &fname); 116 | }; 117 | 118 | 119 | void file_formats_init(); 120 | void file_formats_done(); 121 | 122 | #endif // TIO_H 123 | -------------------------------------------------------------------------------- /translations/cs.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/translations/cs.qm -------------------------------------------------------------------------------- /translations/ru.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psemiletov/eko/a0f061d742a41faa0080b9ccccb25140bbb127c0/translations/ru.qm -------------------------------------------------------------------------------- /utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | this code is Public Domain 3 | Peter Semiletov 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "gui_utils.h" 17 | #include "utils.h" 18 | 19 | 20 | QString qstring_clear (const QString &s) 21 | { 22 | QString t = s; 23 | return t.remove ("&"); 24 | } 25 | 26 | QString qstring_load (const QString &fileName) 27 | { 28 | QFile file (fileName); 29 | 30 | if (! file.open (QFile::ReadOnly | QFile::Text)) 31 | return QString(); 32 | 33 | QTextStream in(&file); 34 | 35 | return in.readAll(); 36 | } 37 | 38 | 39 | bool qstring_save (const QString &fileName, const QString &data) 40 | { 41 | QFile file (fileName); 42 | if (! file.open (QFile::WriteOnly | QFile::Text)) 43 | return false; 44 | 45 | QTextStream out (&file); 46 | out << data; 47 | 48 | return true; 49 | } 50 | 51 | /* 52 | QString string_between (const QString &source, 53 | const QString &sep1, 54 | const QString &sep2) 55 | { 56 | QString result; 57 | int pos1 = source.indexOf (sep1); 58 | if (pos1 == -1) 59 | return result; 60 | 61 | int pos2 = source.indexOf (sep2, pos1 + sep1.size()); 62 | if (pos2 == -1) 63 | return result; 64 | 65 | pos1 += sep1.size(); 66 | 67 | result = source.mid (pos1, pos2 - pos1); 68 | return result; 69 | } 70 | */ 71 | 72 | QString str_from_locale (const char *s) 73 | { 74 | QTextCodec *cd = QTextCodec::codecForLocale(); 75 | QByteArray encodedString = s; 76 | 77 | return cd->toUnicode(encodedString); 78 | } 79 | 80 | 81 | QString get_value_with_default (const QString &val, const QString &def) 82 | { 83 | if (! val.isEmpty()) 84 | return val; 85 | else 86 | return def; 87 | } 88 | 89 | 90 | int get_value_with_default (const QString &val, int def) 91 | { 92 | if (! val.isEmpty()) 93 | return val.toInt(); 94 | else 95 | return def; 96 | } 97 | 98 | 99 | size_t get_value_with_default (const QString &val, size_t def) 100 | { 101 | if (! val.isEmpty()) 102 | return (size_t) val.toInt(); 103 | else 104 | return def; 105 | } 106 | 107 | 108 | float get_value_with_default (const QString &val, float def) 109 | { 110 | if (! val.isEmpty()) 111 | return val.toFloat(); 112 | else 113 | return def; 114 | } 115 | 116 | 117 | QString hash_keyval_to_string (const QHash &h) 118 | { 119 | QStringList l; 120 | 121 | for (auto s: h.keys()) 122 | l.prepend (s.append ("=").append (h.value (s))); 123 | 124 | return l.join ("\n").trimmed(); 125 | } 126 | 127 | 128 | QString map_keyval_to_string (const QMap &h, const QString &sep) 129 | { 130 | QStringList l; 131 | 132 | for (auto s: h.keys()) 133 | l.prepend (s.append (sep).append (h.value (s))); 134 | 135 | return l.join ("\n").trimmed(); 136 | } 137 | 138 | 139 | QString hash_get_val (QHash &h, 140 | const QString &key, 141 | const QString &def_val) 142 | { 143 | QString result = h.value (key); 144 | if (result.isNull() || result.isEmpty()) 145 | { 146 | result = def_val; 147 | h.insert (key, def_val); 148 | } 149 | 150 | return result; 151 | } 152 | 153 | 154 | QHash stringlist_to_hash (const QStringList &l) 155 | { 156 | QHash result; 157 | 158 | if (l.empty()) 159 | return result; 160 | 161 | for (const auto &s: l) 162 | result.insert (s, s); 163 | 164 | return result; 165 | } 166 | 167 | 168 | QHash hash_load (const QString &fname) 169 | { 170 | QHash result; 171 | 172 | if (! file_exists (fname)) 173 | return result; 174 | 175 | result = stringlist_to_hash (qstring_load (fname).split ("\n")); 176 | return result; 177 | } 178 | 179 | 180 | QHash hash_load_keyval (const QString &fname) 181 | { 182 | QHash result; 183 | 184 | if (! file_exists (fname)) 185 | return result; 186 | 187 | QStringList l = qstring_load (fname).split ("\n"); 188 | 189 | for (const auto &s: l) 190 | { 191 | QStringList sl = s.split ("="); 192 | if (sl.size() > 1) 193 | result.insert (sl[0], sl[1]); 194 | } 195 | 196 | return result; 197 | } 198 | 199 | 200 | QMap map_load_keyval (const QString &fname, const QString &sep) 201 | { 202 | QMap result; 203 | 204 | if (! file_exists (fname)) 205 | return result; 206 | 207 | QStringList l = qstring_load (fname).split ("\n"); 208 | 209 | for (const auto &s: l) 210 | { 211 | QStringList sl = s.split (sep); 212 | if (sl.size() > 1) 213 | result.insert (sl[0], sl[1]); 214 | } 215 | 216 | return result; 217 | } 218 | 219 | 220 | QByteArray file_load (const QString &fileName) 221 | { 222 | QFile file (fileName); 223 | QByteArray b; 224 | 225 | if (! file.open (QFile::ReadOnly)) 226 | return b; 227 | 228 | b = file.readAll(); 229 | return b; 230 | } 231 | 232 | 233 | QString file_get_ext (const QString &file_name) 234 | { 235 | if (file_name.isNull() || file_name.isEmpty()) 236 | return QString(); 237 | 238 | int i = file_name.lastIndexOf ("."); 239 | if (i == -1) 240 | return QString(); 241 | 242 | return file_name.mid (i + 1).toLower(); 243 | } 244 | 245 | 246 | QString change_file_ext (const QString &s, const QString &ext) 247 | { 248 | int i = s.lastIndexOf ("."); 249 | if (i == -1) 250 | return (s + "." + ext); 251 | 252 | 253 | QString r (s); 254 | r.truncate (++i); 255 | 256 | r.append (ext); 257 | return r; 258 | } 259 | 260 | 261 | bool file_exists (const QString &fileName) 262 | { 263 | if (fileName.isNull() || fileName.isEmpty()) 264 | return false; 265 | 266 | return QFile::exists (fileName); 267 | } 268 | 269 | 270 | QStringList read_dir_entries (const QString &path) 271 | { 272 | QDir dir (path); 273 | return dir.entryList (QDir::AllEntries | QDir::NoDotAndDotDot); 274 | } 275 | 276 | 277 | QStringList read_dir_files (const QString &path) 278 | { 279 | QDir dir (path); 280 | return dir.entryList (QDir::Files | QDir::NoDotAndDotDot); 281 | } 282 | void CFilesList::iterate (QFileInfo &fi) 283 | { 284 | if (fi.isDir()) 285 | { 286 | QDir d (fi.absoluteFilePath()); 287 | QFileInfoList lfi= d.entryInfoList (QDir::Dirs | QDir::Files | 288 | QDir::Readable | QDir::NoDotAndDotDot); 289 | for (int i = 0; i < lfi.count(); i++) 290 | iterate (lfi[i]); 291 | } 292 | else 293 | if (fi.isFile()) 294 | list.append (fi.absoluteFilePath()); 295 | } 296 | 297 | 298 | void CFilesList::get (const QString &path) 299 | { 300 | list.clear(); 301 | QDir d (path); 302 | QFileInfoList lfi= d.entryInfoList (QDir::Dirs | QDir::Files | 303 | QDir::Readable | QDir::NoDotAndDotDot); 304 | for (int i = 0; i < lfi.count(); i++) 305 | iterate (lfi[i]); 306 | } 307 | 308 | 309 | CFTypeChecker::CFTypeChecker (const QString &fnames, const QString &exts) 310 | { 311 | lexts = qstring_load (exts).split ("\n"); 312 | lnames = qstring_load (fnames).split ("\n"); 313 | } 314 | 315 | 316 | bool CFTypeChecker::check (const QString &fname) 317 | { 318 | bool result = lnames.contains (fname.toLower()); 319 | if (! result) 320 | { 321 | QString ext = file_get_ext (fname); 322 | result = lexts.contains (ext.toLower()); 323 | } 324 | 325 | return result; 326 | } 327 | 328 | 329 | size_t round_to (size_t value, size_t to, bool inc) 330 | { 331 | int i = value; 332 | 333 | if (inc) 334 | { 335 | if (i % to != 0) 336 | i = (i / to) * to + to; 337 | } 338 | else 339 | if (i % to != 0) 340 | i = (i / to) * to; 341 | 342 | return i; 343 | } 344 | 345 | 346 | void qstring_list_print (const QStringList &l) 347 | { 348 | for (const auto &s: l) 349 | qDebug() << s; 350 | } 351 | 352 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | this code is Public Domain 3 | Peter Semiletov 4 | */ 5 | 6 | #ifndef UTILS_H 7 | #define UTILS_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | 21 | class CFilesList: public QObject 22 | { 23 | public: 24 | 25 | QStringList list; 26 | 27 | void get (const QString &path); 28 | void iterate (QFileInfo &fi); 29 | }; 30 | 31 | 32 | class CFTypeChecker: public QObject 33 | { 34 | public: 35 | 36 | QStringList lexts; 37 | QStringList lnames; 38 | 39 | CFTypeChecker (const QString &fnames, const QString &exts); 40 | bool check (const QString &fname); 41 | }; 42 | 43 | 44 | QString qstring_clear (const QString &s); 45 | 46 | 47 | bool is_dir (const QString &path); 48 | 49 | 50 | bool qstring_save (const QString &fileName, const QString &data); 51 | QString qstring_load (const QString &fileName); 52 | 53 | //QString string_between (const QString &source, const QString &sep1, const QString &sep2); 54 | QString str_from_locale (const char *s); 55 | 56 | 57 | float get_value_with_default (const QString &val, float def); 58 | size_t get_value_with_default (const QString &val, size_t def); 59 | int get_value_with_default (const QString &val, int def); 60 | QString get_value_with_default (const QString &val, const QString &def); 61 | 62 | QString hash_keyval_to_string (const QHash &h); 63 | QString hash_get_val (QHash &h, const QString &key, const QString &def_val); 64 | 65 | QMap map_load_keyval (const QString &fname, const QString &sep); 66 | QString map_keyval_to_string (const QMap &h, const QString &sep); 67 | 68 | QHash hash_load (const QString &fname); 69 | QHash hash_load_keyval (const QString &fname); 70 | QHash stringlist_to_hash (const QStringList &l); 71 | 72 | 73 | QByteArray file_load (const QString &fileName); 74 | 75 | QString file_get_ext (const QString &file_name); 76 | QString change_file_ext (const QString &s, const QString &ext); 77 | 78 | bool file_exists (const QString &fileName); 79 | 80 | QStringList read_dir_entries (const QString &path); 81 | QStringList read_dir_files (const QString &path); 82 | 83 | void qstring_list_print (const QStringList &l); 84 | bool is_image (const QString &filename); 85 | 86 | size_t round_to (size_t value, size_t to, bool inc); 87 | 88 | 89 | inline int get_value (int total, int perc) 90 | { 91 | return static_cast (total * perc / 100); 92 | } 93 | 94 | 95 | inline float get_fvalue (float total, float perc) 96 | { 97 | return (total * perc / 100); 98 | } 99 | 100 | 101 | inline double get_percent (double total, double value) 102 | { 103 | return (value / total) * 100; 104 | } 105 | 106 | 107 | inline float get_percent (float total, float value) 108 | { 109 | return (value / total) * 100; 110 | } 111 | 112 | 113 | inline bool is_dir (const QString &path) 114 | { 115 | return QFileInfo(path).isDir(); 116 | } 117 | 118 | 119 | inline QString get_file_path (const QString &fileName) 120 | { 121 | return QFileInfo (fileName).absolutePath(); 122 | } 123 | 124 | 125 | inline bool float_greater_than (float a, float b) 126 | { 127 | return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * std::numeric_limits::epsilon()); 128 | } 129 | 130 | 131 | inline bool float_less_than (float a, float b) 132 | { 133 | return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * std::numeric_limits::epsilon()); 134 | } 135 | 136 | 137 | inline bool float_equal (float x, float y) 138 | { 139 | return std::abs(x - y) <= std::numeric_limits::epsilon() * std::abs(x); 140 | } 141 | 142 | 143 | inline float conv (float v, float middle, float max) 144 | { 145 | if (v == middle) 146 | return 0; 147 | 148 | if (v > middle) 149 | return (max - middle - v); 150 | else 151 | return middle - v; 152 | } 153 | 154 | 155 | inline float conv_to_db (float v, float v_min, float v_max, float range_negative, float range_positive) 156 | { 157 | if (v == 0) 158 | return 0; 159 | 160 | if (v > 0) 161 | { 162 | float x = v_max / range_positive; 163 | float y = v_max / v; 164 | 165 | return v / (y * x); 166 | } 167 | else 168 | { 169 | float x = v_min / range_negative; 170 | float y = v_min / v; 171 | 172 | return v / (y * x); 173 | } 174 | } 175 | 176 | 177 | inline float scale_val (float val, float from_min, float from_max, float to_min, float to_max) 178 | { 179 | return (val - from_min) * (to_max - to_min) / 180 | (from_max - from_min) + to_min; 181 | } 182 | 183 | 184 | inline QString frames_to_time_str (size_t frames, size_t samplerate) 185 | { 186 | size_t msecs = (float) frames / samplerate * 1000; 187 | 188 | QTime a (0, 0); 189 | a = a.addMSecs ((int) msecs); 190 | 191 | return a.toString ("hh:mm:ss.zzz"); 192 | } 193 | 194 | 195 | inline size_t msecs_to_frames (size_t msecs, size_t samplerate) 196 | { 197 | return samplerate * msecs / 1000; 198 | } 199 | 200 | 201 | inline QTime frames_to_time (size_t frames, size_t samplerate) 202 | { 203 | size_t msecs = (float) frames / samplerate * 1000; 204 | QTime a (0, 0); 205 | a = a.addMSecs ((int) msecs); 206 | return a; 207 | } 208 | 209 | #endif 210 | --------------------------------------------------------------------------------