diff --git a/.travis/linux..script.sh b/.travis/linux..script.sh index d89b130db..c9de77d36 100644 --- a/.travis/linux..script.sh +++ b/.travis/linux..script.sh @@ -1 +1 @@ -cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. +cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_WERROR=ON .. diff --git a/.travis/linux.win32.before_install.sh b/.travis/linux.win32.before_install.sh index 02a9be79d..73c14aedd 100644 --- a/.travis/linux.win32.before_install.sh +++ b/.travis/linux.win32.before_install.sh @@ -1,2 +1,2 @@ -sudo add-apt-repository ppa:tobydox/mingw -y +sudo add-apt-repository ppa:tobydox/mingw-x-precise -y sudo apt-get update -qq diff --git a/.travis/linux.win32.script.sh b/.travis/linux.win32.script.sh index 3831a842f..b0743d295 100644 --- a/.travis/linux.win32.script.sh +++ b/.travis/linux.win32.script.sh @@ -1 +1,2 @@ +export CMAKE_OPTS="-DUSE_WERROR=ON" ../build_mingw32 || ../build_mingw32 diff --git a/.travis/linux.win64.script.sh b/.travis/linux.win64.script.sh index 7c6c4f96a..ba79da8ca 100644 --- a/.travis/linux.win64.script.sh +++ b/.travis/linux.win64.script.sh @@ -1 +1,2 @@ +export CMAKE_OPTS="-DUSE_WERROR=ON" ../build_mingw64 || ../build_mingw64 diff --git a/.travis/osx..script.sh b/.travis/osx..script.sh index d89b130db..d594e58f6 100644 --- a/.travis/osx..script.sh +++ b/.travis/osx..script.sh @@ -1 +1 @@ -cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. +cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. -DUSE_WERROR=OFF diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cb740777..a526df3df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -358,7 +358,8 @@ CONFIGURE_FILE("${CMAKE_SOURCE_DIR}/plugins/zynaddsubfx/zynaddsubfx.rc.in" "${CM # set compiler flags SET(WERROR_FLAGS "-Wall -Werror=unused-function -Wno-sign-compare -Wno-strict-overflow") -IF(NOT LMMS_BUILD_APPLE) +OPTION(USE_WERROR "Add -werror to the build flags. Stops the build on warnings" OFF) +IF(${USE_WERROR}) SET(WERROR_FLAGS "${WERROR_FLAGS} -Werror") ENDIF() diff --git a/data/locale/sv.ts b/data/locale/sv.ts index 6f57e6f6f..85198a1eb 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -5,27 +5,27 @@ AboutDialog About LMMS - + Om LMMS Version %1 (%2/%3, Qt %4, %5) - + Version %1 (%2/%3, Qt %4, %5) About - Om + Om LMMS - easy music production for everyone - + LMMS - enkel musikproduktion för alla Authors - + Medverkande Translation - + Översättning Current language not translated (or native English). @@ -35,11 +35,11 @@ If you're interested in translating LMMS in another language or want to imp License - + Licens Copyright (c) 2004-2014, LMMS developers - + Copyright (c) 2004-2014, LMMS utvecklare <html><head/><body><p><a href="http://lmms.io"><span style=" text-decoration: underline; color:#0000ff;">http://lmms.io</span></a></p></body></html> @@ -47,26 +47,26 @@ If you're interested in translating LMMS in another language or want to imp LMMS - + LMMS Involved - + Involverad Contributors ordered by number of commits: - + Medverkande, ordnade efter mängd bidrag: AmplifierControlDialog VOL - VOL + VOL Volume: - Volym: + Volym: PAN @@ -78,26 +78,26 @@ If you're interested in translating LMMS in another language or want to imp LEFT - + VÄNSTER Left gain: - + Vänster förstärkning: RIGHT - + HÖGER Right gain: - + Höger förstärkning: AmplifierControls Volume - Volym + Volym Panning @@ -105,398 +105,398 @@ If you're interested in translating LMMS in another language or want to imp Left gain - + Vänster förstärkning Right gain - + Höger förstärkning AudioAlsa::setupWidget DEVICE - ENHET + ENHET CHANNELS - KANALER + KANALER AudioFileProcessorView Open other sample - + Oppna annan ljudfil Click here, if you want to open another audio-file. A dialog will appear where you can select your file. Settings like looping-mode, start and end-points, amplify-value, and so on are not reset. So, it may not sound like the original sample. - + Klicka här för att öppna en annan ljudfil. En dialog visas där du väljer din fil. Inställningar som looping, start och slutpunkter, amplifiering och sådant omställs inte. Därför låter det kanske inte som originalfilen. Reverse sample - + Spela baklänges If you enable this button, the whole sample is reversed. This is useful for cool effects, e.g. a reversed crash. - + Den här knappen gör att ljudfilen spelas baklänges. Den kan användas för intressanta effeker t.ex. en baklänges cymbal. Amplify: - Förstärkning: + Förstärkning: With this knob you can set the amplify ratio. When you set a value of 100% your sample isn't changed. Otherwise it will be amplified up or down (your actual sample-file isn't touched!) - + Med detta vred ställer du in förstärkningen. Vid 100% blir det ingen skillnad. Annars blir din ljudfil mer eller mindre högljudd, men originalfilen förändras inte. Startpoint: - Startpunkt: + Startpunkt: Endpoint: - + Slutpunkt: Continue sample playback across notes - + Forsätt spela ljudfil över noter Enabling this option makes the sample continue playing across different notes - if you change pitch, or the note length stops before the end of the sample, then the next note played will continue where it left off. To reset the playback to the start of the sample, insert a note at the bottom of the keyboard (< 20 Hz) - + Denna inställningen gör att ljudfilen förtsätter spela över noter. Om en not avslutas före ljudfilen är slut fortsätter nästa not där den förra slutade. Om du vill starta från början av ljudfilen innan den spelat färdigt, placera en not på botten av pianot (vid 20Hz) Disable loop - + Avaktivera looping This button disables looping. The sample plays only once from start to end. - + Den här knappen avaktiverar looping. Ljudfilen spelas bara en gång från start till slut. Enable loop - + Aktivera looping This button enables forwards-looping. The sample loops between the end point and the loop point. - + Den här knappen aktiverar looping. Ljudfilen loopar mellan slutpunkten och looppunkten. This button enables ping-pong-looping. The sample loops backwards and forwards between the end point and the loop point. - + Den här knappen aktiverar "ping-pong" looping. Ljudfilen spelar från start till slut, och sen tilbaks, och fortsäter så. With this knob you can set the point where AudioFileProcessor should begin playing your sample. - + Med den här vreden ställer du in vartifrån ljudfilen ska börja spela. With this knob you can set the point where AudioFileProcessor should stop playing your sample. - + Med den här vreden ställer du in vart ljudfilen slutar spela. Loopback point: - + Loopback punkt: With this knob you can set the point where the loop starts. - + Den här vreden ställer in vart loopen startar. AudioFileProcessorWaveView Sample length: - + Ljudfilens längd: AudioJack JACK client restarted - + JACK klienten omstartades LMMS was kicked by JACK for some reason. Therefore the JACK backend of LMMS has been restarted. You will have to make manual connections again. - + LMMS blev bortkopplat från JACK. LMMS JACK backend omstartades därfor. Du får manuellt koppla om igen. JACK server down - + JACK server nerstängd The JACK server seems to have been shutdown and starting a new instance failed. Therefore LMMS is unable to proceed. You should save your project and restart JACK and LMMS. - + JACK servern stängde av och det gick inte starta en ny. LMMS kan inte fortsätta. Du bör spara ditt projekt och starta om både JACK och LMMS. CLIENT-NAME - KLIENT-NAMN + KLIENT-NAMN CHANNELS - KANALER + KANALER AudioOss::setupWidget DEVICE - ENHET + ENHET CHANNELS - KANALER + KANALER AudioPortAudio::setupWidget BACKEND - + BACKEND DEVICE - ENHET + ENHET AudioPulseAudio::setupWidget DEVICE - ENHET + ENHET CHANNELS - KANALER + KANALER AudioSdl::setupWidget DEVICE - ENHET + ENHET AutomatableModel &Reset (%1%2) - &Nollställ (%1%2) + &Nollställ (%1%2) &Copy value (%1%2) - + Kopiera värde (%1%2) &Paste value (%1%2) - &Klistra in värde (%1%2) + &Klistra in värde (%1%2) Edit song-global automation - + Redigera global automation Connected to %1 - + Kopplad till %1 Connected to controller - + Kopplad till controller Edit connection... - + Redigera koppling... Remove connection - + Ta bort koppling Connect to controller... - + Koppla till kontroller... Remove song-global automation - + Ta bort global automation Remove all linked controls - + Ta bort alla kopplade kontroller AutomationEditor Please open an automation pattern with the context menu of a control! - + Öppna ett automationsmönster ifrån en kontrollers kontextmeny! Values copied - Värden kopierade + Värden kopierade All selected values were copied to the clipboard. - Alla valda värden blev kopierade till urklipp. + Alla valda värden blev kopierade till urklipp. AutomationEditorWindow Play/pause current pattern (Space) - Spela/pausa aktuellt mönster (mellanslag) + Spela/pausa aktuellt mönster (mellanslag) Click here if you want to play the current pattern. This is useful while editing it. The pattern is automatically looped when the end is reached. - + Clicka här för att spela det aktuella mönstret. Det här är hjälpsamt när man redigerar. Mönstret spelas från början igen när de nått sitt slut. Stop playing of current pattern (Space) - Sluta spela aktuellt mönster (mellanslag) + Sluta spela aktuellt mönster (mellanslag) Click here if you want to stop playing of the current pattern. - + Klicka här för att stoppa uppspelning av de aktuella mönstret. Draw mode (Shift+D) - + Ritläge (Shift+D) Erase mode (Shift+E) - + Suddläge (Shift+E) Flip vertically - + Spegla vertikalt Flip horizontally - + Spegla horizontellt Click here and the pattern will be inverted.The points are flipped in the y direction. - + Klicka här för att spegla mönstret. Punkterna förflyttas på y-axeln Click here and the pattern will be reversed. The points are flipped in the x direction. - + Klicka här för att spegla mönstret. Punkterna förflyttas på x-axeln Click here and draw-mode will be activated. In this mode you can add and move single values. This is the default mode which is used most of the time. You can also press 'Shift+D' on your keyboard to activate this mode. - + Klicka här för att aktivera ritläget. I detta läget kan du lägga till och förflytta individuella värden. Det här är standardläget. Det går också att trycka 'Shift+D' på tangentborded för att aktivera detta läget. Click here and erase-mode will be activated. In this mode you can erase single values. You can also press 'Shift+E' on your keyboard to activate this mode. - + Klicka här för att aktivera suddläget. I detta läget kan du ta bort individuella värden. Det går också att trycka 'Shift+E' på tangentborded för att aktivera detta läget. Discrete progression - + Diskret talföljd Linear progression - + Linjär talföljd Cubic Hermite progression - + Cubic Hermite talföljd Tension value for spline - + Spänning i mönstrets spline A higher tension value may make a smoother curve but overshoot some values. A low tension value will cause the slope of the curve to level off at each control point. - + Högre spänning ger en mjuk kurva som ibland missar individuella punkter. Med lägre spänning planar kurvan ut nära punkterna. Click here to choose discrete progressions for this automation pattern. The value of the connected object will remain constant between control points and be set immediately to the new value when each control point is reached. - + Klicka här för att aktivera diskret talföljd. Värdet är konstant mella kontroll punkter och ändras direkt när en ny kontrollpunkt nås. Click here to choose linear progressions for this automation pattern. The value of the connected object will change at a steady rate over time between control points to reach the correct value at each control point without a sudden change. - + Klicka här för att aktivera linjär talföljd. Värdet ändras vid en stadig takt mellan kontrollpunkter för att gradvis nå nästa värde. Click here to choose cubic hermite progressions for this automation pattern. The value of the connected object will change in a smooth curve and ease in to the peaks and valleys. - + Klicka här för att aktivera cubic hermite talföljd. Värdet följer en mjuk kurva mellan kontrollpunkter. Cut selected values (Ctrl+X) - klipp ut valda värden (ctrl+X) + Klipp ut valda värden (Ctrl+X) Copy selected values (Ctrl+C) - Kopiera valda värden (ctrl+C) + Kopiera valda värden (ctrl+C) Paste values from clipboard Ctrl+V) - + Klistra värden (Ctrl+V) Click here and selected values will be cut into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - + Klicka här för att klippa de valda värderna. Du kan sen klistra dem var som helst genom att klicka på klistra knappen. Click here and selected values will be copied into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - + Klicka här för att kopiera de valda värderna. Du kan sedan klistra dem var som helst genom att klicka på klistra knappen. Click here and the values from the clipboard will be pasted at the first visible measure. - + Klicka här för att klistra kopierade värderna vid den första synliga metern. Tension: - + Spänning: Automation Editor - no pattern - + Redigera Automation - inget automationsmönster Automation Editor - %1 - + Redigera Automation - %1 AutomationPattern Drag a control while pressing <Ctrl> - + Dra en kontroll samtidigt som du håller <Ctrl> Model is already connected to this pattern. - + Modellen är redan kopplad till detta mönstret. AutomationPatternView double-click to open this pattern in automation editor - + dubbelklicka för att öppna det här automationsmönstret för redigering Open in Automation editor - + Redigera automationsmönster Clear - + Rensa Reset name - Nollställ namn + Nollställ namn Change name - Byt namn + Byt namn %1 Connections - + %1 Kopplingar Disconnect "%1" - + Avkoppla "%1" Set/clear record @@ -504,152 +504,152 @@ If you're interested in translating LMMS in another language or want to imp Flip Vertically (Visible) - + Spegla Vertikalt (Synligt) Flip Horizontally (Visible) - + Spegla Horizontellt (Synligt) AutomationTrack Automation track - + Automationsspår BBEditor Beat+Bassline Editor - + Redigera Trummor+Bas Play/pause current beat/bassline (Space) - + Spela/pause Trummor+Bas Stop playback of current beat/bassline (Space) - + Avsluta uppspelning av trummor/bas Click here to play the current beat/bassline. The beat/bassline is automatically looped when its end is reached. - + Klicka här för att spela trummor/bas. Mönstret loopar när det nåt sitt slut. Click here to stop playing of current beat/bassline. - + Klicka här för att sluta spela trummor/bas. Add beat/bassline - + Lägg till trummor/bas Add automation-track - + Lägg till automationsspår Remove steps - + Ta bort steg Add steps - + Lägg till steg BBTCOView Open in Beat+Bassline-Editor - + Redigera Trummor+Bas Reset name - Nollställ namn + Nollställ namn Change name - Byt namn + Byt namn Change color - Byt färg + Byt färg Reset color to default - + Byt färg till standard BBTrack Beat/Bassline %1 - + Trum/Basmönster %1 Clone of %1 - + Kopia av %1 BassBoosterControlDialog FREQ - + FREQ Frequency: - + Frekvens: GAIN - + FÖRST Gain: - + Förstärkning: RATIO - + RATIO Ratio: - + Ratio: BassBoosterControls Frequency - + Frekvens Gain - + Förstärkning Ratio - + Ratio BitcrushControlDialog IN - + IN OUT - + UT GAIN - + FÖRST Input Gain: - + Input Förstärkning: NOIS @@ -661,7 +661,7 @@ If you're interested in translating LMMS in another language or want to imp Output Gain: - + Output Förstärkning CLIP @@ -685,11 +685,11 @@ If you're interested in translating LMMS in another language or want to imp Depth - + Djup Depth Enabled - + Djup aktiverat Enable bitdepth-crushing @@ -709,22 +709,22 @@ If you're interested in translating LMMS in another language or want to imp Levels - + Nivåer Levels: - + Nivåer: CaptionMenu &Help - &Hjälp + &Hjälp Help (not available) - + Hjälp (inte tillgängligt) @@ -742,38 +742,38 @@ If you're interested in translating LMMS in another language or want to imp Controller Controller %1 - + Kontroller %1 ControllerConnectionDialog Connection Settings - + Kopplingsinställningar MIDI CONTROLLER - + MIDI KONTROLLER Input channel - + Inputkanal CHANNEL - KANAL + KANAL Input controller - + Inputkontroller CONTROLLER - + KONTROLLER Auto Detect - + Upptäck Automatiskt MIDI-devices to receive MIDI-events from @@ -781,7 +781,7 @@ If you're interested in translating LMMS in another language or want to imp USER CONTROLLER - + ANVÄNDARKONTROLLER MAPPING FUNCTION @@ -789,15 +789,15 @@ If you're interested in translating LMMS in another language or want to imp OK - + OK Cancel - Avbryt + Avbryt LMMS - + LMMS Cycle Detected. @@ -812,38 +812,38 @@ If you're interested in translating LMMS in another language or want to imp Add - Lägg till + Lägg till Confirm Delete - + Bekräfta Borttagning Confirm delete? There are existing connection(s) associted with this controller. There is no way to undo. - + Vill du verkligen ta bort? Det finns kopplingar till den här kontrollern, och operationen går inte ångra. ControllerView Controls - Kontroller + Kontroller Controllers are able to automate the value of a knob, slider, and other controls. - + Kontroller kan automatisera värdet på en vred, reglage, och andra kontroller Rename controller - + Byt namn på kontroller Enter the new name for this controller - + Skriv nya namnet på kontrollern &Remove this plugin - &Ta bort denna pluginen + @@ -1124,7 +1124,7 @@ If you're interested in translating LMMS in another language or want to imp DummyEffect NOT FOUND - + HITTAS INTE @@ -1468,7 +1468,7 @@ Right clicking will bring up a context menu where you can change the order in wh Click here for a user-defined wave. Afterwards, drag an according sample-file onto the LFO graph. - + Klicka här för att använda en annan vågform. Dra sedan en ljudfil till LFO grafen FREQ x 100 @@ -1504,7 +1504,7 @@ Right clicking will bring up a context menu where you can change the order in wh Drag a sample from somewhere and drop it in this window. - + Dra en ljudfil till det här fönstret Click here for random wave. @@ -1958,11 +1958,11 @@ Please make sure you have write-permission to the file and the directory contain Loading sample - + Laddar ljudfil Please wait, loading sample for preview... - + Ljudfilen laddas för förhandsvisning... --- Factory files --- @@ -3559,19 +3559,19 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. My Samples - + Mina Ljudfiler My Presets - + Mina Presets My Home - + Mit Hem My Computer - + Min Dator Root Directory @@ -3579,15 +3579,15 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. &File - + &Fil &Recently Opened Projects - + &Nyligen Öppnade Project Save as New &Version - + Spara som ny &Version E&xport Tracks... @@ -3599,15 +3599,15 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. What's This? - + Vad är det här? Open Project - + Öppna Project Save Project - + SparaProject @@ -5323,7 +5323,7 @@ Reason: "%2" SampleTrack Sample track - + Ljudfil spår Volume @@ -5748,7 +5748,7 @@ Latency: %2 ms Add sample-track - + Lägg til ljudfil-spår Add automation-track @@ -6621,7 +6621,7 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Click to load a waveform from a sample file - + Klicka för att ladda in en vågform från en ljudfil Phase left @@ -6802,7 +6802,7 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle audioFileProcessor Reverse sample - + Spela baklänges Amplify @@ -6810,11 +6810,11 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Start of sample - + Start på ljudfil End of sample - + Slut på ljudfil Stutter @@ -6846,21 +6846,21 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Sample not found: %1 - + Ljudfil hittades inte: %1 bitInvader Samplelength - + Ljudfilslängd bitInvaderView Sample Length - + Ljudfilens längd Sine wave @@ -6868,7 +6868,7 @@ Se till att du har läsningsrättigheter för filen och katalogen som innehålle Triangle wave - triganelvåg + Triganelvåg Saw wave diff --git a/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz b/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz new file mode 100644 index 000000000..0a2ecb2c9 Binary files /dev/null and b/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz differ diff --git a/data/projects/CoolSongs/LICENSES.TXT b/data/projects/CoolSongs/LICENSES.TXT index 369d90148..513efd613 100644 --- a/data/projects/CoolSongs/LICENSES.TXT +++ b/data/projects/CoolSongs/LICENSES.TXT @@ -13,7 +13,11 @@ * Farbro-Tectonic.mmpz - CC (by) - http://lmms.io/lsp/index.php?action=show&file=1327 - + +* Greippi - Krem Kaakkuja (Second Flight Remix) + - CC (by) + - http://lmms.io/lsp/index.php?action=show&file=6337 + * Greippi-ardudar.mmpz - CC (by-sa) - http://lmms.io/lsp/index.php?action=show&file=4916 @@ -57,7 +61,7 @@ * TameAnderson-MakeMe.mmpz - Artistic 2.0 - http://lmms.io/lsp/index.php?action=show&file=1060 - + * unfa-Spoken.mmpz - CC (by-nc) - http://lmms.io/lsp/index.php?action=show&file=4929 diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 92f7df68e..57c2a6f0f 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -25,7 +25,6 @@ #ifndef AUTOMATABLE_MODEL_H #define AUTOMATABLE_MODEL_H -#include "lmms_math.h" #include #include "JournallingObject.h" @@ -174,7 +173,7 @@ public: { return castValue( m_step ); } - + //! @brief Returns value scaled with the scale type and min/max values of this model float scaledValue( float value ) const; //! @brief Returns value applied with the inverse of this model's scale type @@ -265,22 +264,22 @@ public: } float globalAutomationValueAt( const MidiTime& time ); - + bool hasStrictStepSize() const { return m_hasStrictStepSize; } - + void setStrictStepSize( const bool b ) { m_hasStrictStepSize = b; } - + static void incrementPeriodCounter() { ++s_periodCounter; } - + static void resetPeriodCounter() { s_periodCounter = 0; @@ -333,13 +332,13 @@ private: float m_step; float m_range; float m_centerValue; - + bool m_valueChanged; // currently unused? float m_oldValue; int m_setValueDepth; - + // used to determine if step size should be applied strictly (ie. always) // or only when value set from gui (default) bool m_hasStrictStepSize; @@ -357,9 +356,9 @@ private: ValueBuffer m_valueBuffer; long m_lastUpdatedPeriod; static long s_periodCounter; - + bool m_hasSampleExactData; - + // prevent several threads from attempting to write the same vb at the same time QMutex m_valueBufferMutex; diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 64cfeb718..eca52d2c6 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -262,6 +262,9 @@ public: void setCurrentPattern(AutomationPattern* pattern); const AutomationPattern* currentPattern(); + virtual void dropEvent( QDropEvent * _de ); + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + void open(AutomationPattern* pattern); AutomationEditor* m_editor; diff --git a/include/BBEditor.h b/include/BBEditor.h index abd325bc2..aea2f8763 100644 --- a/include/BBEditor.h +++ b/include/BBEditor.h @@ -57,9 +57,6 @@ public slots: void play(); void stop(); -protected: - virtual void closeEvent( QCloseEvent * _ce ); - private: BBTrackContainerView* m_trackContainerView; ComboBox * m_bbComboBox; @@ -80,13 +77,16 @@ public: void removeBBView(int bb); + void saveSettings(QDomDocument& doc, QDomElement& element); + void loadSettings(const QDomElement& element); + public slots: void addSteps(); void removeSteps(); void addAutomationTrack(); protected slots: - virtual void dropEvent(QDropEvent * de ); + void dropEvent(QDropEvent * de ); void updatePosition(); private: diff --git a/include/BBTrackContainer.h b/include/BBTrackContainer.h index a224495f0..a9e1eb3c2 100644 --- a/include/BBTrackContainer.h +++ b/include/BBTrackContainer.h @@ -27,7 +27,7 @@ #define BB_TRACK_CONTAINER_H #include "TrackContainer.h" -#include "ComboBox.h" +#include "ComboBoxModel.h" class EXPORT BBTrackContainer : public TrackContainer diff --git a/include/BandLimitedWave.h b/include/BandLimitedWave.h index 1c81e0606..d8f1eae13 100644 --- a/include/BandLimitedWave.h +++ b/include/BandLimitedWave.h @@ -26,11 +26,9 @@ #ifndef BANDLIMITEDWAVE_H #define BANDLIMITEDWAVE_H -#include -#include -#include +class QDataStream; +class QString; -#include "ConfigManager.h" #include "export.h" #include "interpolation.h" #include "lmms_basics.h" diff --git a/include/BufferManager.h b/include/BufferManager.h index c2a0a987c..b40b43143 100644 --- a/include/BufferManager.h +++ b/include/BufferManager.h @@ -22,17 +22,14 @@ * Boston, MA 02110-1301 USA. * */ - + #ifndef BUFFER_MANAGER_H #define BUFFER_MANAGER_H -#include "MemoryManager.h" +#include "export.h" #include "lmms_basics.h" -#include "Engine.h" -#include "Mixer.h" -#include -#include +class QAtomicInt; const int BM_INITIAL_BUFFERS = 512; //const int BM_INCREMENT = 64; @@ -45,11 +42,11 @@ public: static void release( sampleFrame * buf ); static void refresh(); // static void extend( int c ); - + private: static sampleFrame ** s_available; static QAtomicInt s_availableIndex; - + static sampleFrame ** s_released; static QAtomicInt s_releasedIndex; // static QReadWriteLock s_mutex; diff --git a/include/ComboBoxModel.h b/include/ComboBoxModel.h index 8c1e64c83..5af4355f0 100644 --- a/include/ComboBoxModel.h +++ b/include/ComboBoxModel.h @@ -29,7 +29,6 @@ #include #include "AutomatableModel.h" -#include "templates.h" class PixmapLoader; diff --git a/include/DataFile.h b/include/DataFile.h index 57db8905f..1d5f71f78 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -28,12 +28,12 @@ #define DATA_FILE_H #include -#include #include "export.h" -#include "lmms_basics.h" #include "MemoryManager.h" +class QTextStream; + class EXPORT DataFile : public QDomDocument { MM_OPERATORS diff --git a/include/DrumSynth.h b/include/DrumSynth.h index e57499038..e29c4bc2c 100644 --- a/include/DrumSynth.h +++ b/include/DrumSynth.h @@ -3,7 +3,7 @@ * * Copyright (c) 1998-2000 Paul Kellett (mda-vst.com) * Copyright (c) 2007 Paul Giblock - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -42,11 +42,11 @@ class DrumSynth { void GetEnv(int env, const char *sec, const char *key, const char *ini); float waveform(float ph, int form); - + int GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file); int GetPrivateProfileInt(const char *sec, const char *key, int def, const char *file); float GetPrivateProfileFloat(const char *sec, const char *key, float def, const char *file); }; -#endif +#endif diff --git a/include/Engine.h b/include/Engine.h index 55dd9021e..ad7abe399 100644 --- a/include/Engine.h +++ b/include/Engine.h @@ -26,28 +26,17 @@ #ifndef ENGINE_H #define ENGINE_H -#include "lmmsconfig.h" -#include "MemoryManager.h" - #include #include "export.h" -class AutomationEditorWindow; -class BBEditor; class BBTrackContainer; class DummyTrackContainer; class FxMixer; -class FxMixerView; class ProjectJournal; -class MainWindow; class Mixer; -class PianoRollWindow; -class ProjectNotes; class Song; -class SongEditorWindow; class Ladspa2LMMS; -class ControllerRackView; class EXPORT Engine diff --git a/include/FadeButton.h b/include/FadeButton.h index 6e7371f9f..4f05b3491 100644 --- a/include/FadeButton.h +++ b/include/FadeButton.h @@ -39,6 +39,7 @@ public: _activated_color, QWidget * _parent ); virtual ~FadeButton(); + void setActiveColor( const QColor & activated_color ); public slots: diff --git a/include/Instrument.h b/include/Instrument.h index 70831b0ea..fdacce603 100644 --- a/include/Instrument.h +++ b/include/Instrument.h @@ -26,17 +26,18 @@ #ifndef INSTRUMENT_H #define INSTRUMENT_H -#include - +#include +#include +#include "export.h" +#include "lmms_basics.h" +#include "MemoryManager.h" +#include "MidiTime.h" #include "Plugin.h" -#include "Mixer.h" // forward-declarations class InstrumentTrack; -class InstrumentView; class MidiEvent; -class MidiTime; class NotePlayHandle; class Track; diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index 16536c081..8c8c963fa 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -306,6 +306,9 @@ public: static void cleanupWindowCache(); + // Create a menu for assigning/creating channels for this track + QMenu * createFxMenu( QString title, QString newFxLabel ); + protected: virtual void dragEnterEvent( QDragEnterEvent * _dee ); @@ -320,6 +323,10 @@ private slots: void midiInSelected(); void midiOutSelected(); void midiConfigChanged(); + void muteChanged(); + + void assignFxLine( int channelIndex ); + void createFxLine(); private: @@ -374,6 +381,12 @@ public: void setInstrumentTrackView( InstrumentTrackView * _tv ); + InstrumentTrackView *instrumentTrackView() + { + return m_itv; + } + + PianoView * pianoView() { return m_pianoView; diff --git a/include/MemoryManager.h b/include/MemoryManager.h index 44ef58c60..559e90869 100644 --- a/include/MemoryManager.h +++ b/include/MemoryManager.h @@ -28,11 +28,12 @@ #include #include -#include #include #include "MemoryHelper.h" #include "export.h" +class QReadWriteLock; + const int MM_CHUNK_SIZE = 64; // granularity of managed memory const int MM_INITIAL_CHUNKS = 1024 * 1024; // how many chunks to allocate at startup - TODO: make configurable const int MM_INCREMENT_CHUNKS = 16 * 1024; // min. amount of chunks to increment at a time diff --git a/include/MixerWorkerThread.h b/include/MixerWorkerThread.h index 5f5c18c84..e95c13a3b 100644 --- a/include/MixerWorkerThread.h +++ b/include/MixerWorkerThread.h @@ -28,15 +28,9 @@ #include #include -#include "ThreadableJob.h" -#include "Mixer.h" - -#ifdef __SSE__ -#include -#endif -#ifdef __SSE3__ -#include -#endif +class QWaitCondition; +class Mixer; +class ThreadableJob; class MixerWorkerThread : public QThread { diff --git a/include/Model.h b/include/Model.h index 9f0590e25..c62c52ebd 100644 --- a/include/Model.h +++ b/include/Model.h @@ -25,8 +25,8 @@ #ifndef MODEL_H #define MODEL_H +#include #include -#include #include "export.h" diff --git a/include/ModelView.h b/include/ModelView.h index 9e323a947..866546061 100644 --- a/include/ModelView.h +++ b/include/ModelView.h @@ -25,6 +25,7 @@ #ifndef MODEL_VIEW_H #define MODEL_VIEW_H +#include #include "Model.h" diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index d2cf1c0fc..9cabdc346 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -26,14 +26,13 @@ #ifndef NOTE_PLAY_HANDLE_H #define NOTE_PLAY_HANDLE_H -#include "lmmsconfig.h" #include "Note.h" #include "PlayHandle.h" #include "Track.h" #include "MemoryManager.h" -#include -#include +class QAtomicInt; +class QReadWriteLock; class InstrumentTrack; class NotePlayHandle; @@ -59,7 +58,7 @@ public: OriginCount }; typedef Origins Origin; - + NotePlayHandle( InstrumentTrack* instrumentTrack, const f_cnt_t offset, const f_cnt_t frames, @@ -83,9 +82,9 @@ public: { return m_midiChannel; } - + /*! convenience function that returns offset for the first period and zero otherwise, - used by instruments to handle the offset: instruments have to check this property and + used by instruments to handle the offset: instruments have to check this property and add the correct number of empty frames in the beginning of the period */ f_cnt_t noteOffset() const { diff --git a/include/Oscillator.h b/include/Oscillator.h index de7aee66b..e146b5af0 100644 --- a/include/Oscillator.h +++ b/include/Oscillator.h @@ -36,8 +36,6 @@ #include "SampleBuffer.h" #include "lmms_constants.h" - -class SampleBuffer; class IntModel; diff --git a/include/PianoRoll.h b/include/PianoRoll.h index bc2a0d8cb..f4f313174 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -160,6 +160,8 @@ protected slots: void hidePattern( Pattern* pattern ); + void selectRegionFromPixels( int xStart, int xEnd ); + signals: void currentPatternChanged(); @@ -229,7 +231,7 @@ private: inline int noteEditRight() const; inline int noteEditLeft() const; - void dragNotes( int x, int y, bool alt, bool shift ); + void dragNotes( int x, int y, bool alt, bool shift, bool ctrl ); static const int cm_scrollAmtHoriz = 10; static const int cm_scrollAmtVert = 1; @@ -295,7 +297,7 @@ private: int m_oldNotesEditHeight; int m_notesEditHeight; - int m_ppt; + int m_ppt; // pixels per tact int m_totalKeysToScroll; // remember these values to use them diff --git a/include/Plugin.h b/include/Plugin.h index 5efcf68b7..4bed7307d 100644 --- a/include/Plugin.h +++ b/include/Plugin.h @@ -148,8 +148,8 @@ public: // returns display-name out of descriptor virtual QString displayName() const { - return Model::displayName().isEmpty() - ? m_descriptor->displayName + return Model::displayName().isEmpty() + ? m_descriptor->displayName : Model::displayName(); } diff --git a/include/TimeLineWidget.h b/include/TimeLineWidget.h index 417ceb530..f962657e6 100644 --- a/include/TimeLineWidget.h +++ b/include/TimeLineWidget.h @@ -35,6 +35,7 @@ class QPixmap; class QToolBar; class NStateButton; class TextFloat; +class SongEditor; class TimeLineWidget : public QWidget, public JournallingObject @@ -128,6 +129,11 @@ public: m_ppt / MidiTime::ticksPerTact() ); } +signals: + + void regionSelectedFromPixels( int, int ); + void selectionFinished(); + public slots: void updatePosition( const MidiTime & ); @@ -171,6 +177,7 @@ private: TextFloat * m_hint; + int m_initalXSelect; enum actions @@ -178,7 +185,8 @@ private: NoAction, MovePositionMarker, MoveLoopBegin, - MoveLoopEnd + MoveLoopEnd, + SelectSongTCO, } m_action; int m_moveXOff; diff --git a/include/Track.h b/include/Track.h index 227abf135..1bebffbf1 100644 --- a/include/Track.h +++ b/include/Track.h @@ -391,8 +391,6 @@ private slots: void recordingOn(); void recordingOff(); void clearTrack(); - void assignFxLine( int channelIndex ); - void createFxLine(); private: static QPixmap * s_grip; diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index fdf28be91..42e56128f 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -126,6 +126,17 @@ public slots: virtual void dropEvent( QDropEvent * _de ); virtual void dragEnterEvent( QDragEnterEvent * _dee ); + /// + /// \brief selectRegionFromPixels + /// \param x + /// \param y + /// Use the rubber band to select TCO from all tracks using x, y pixels + void selectRegionFromPixels(int xStart, int xEnd); + + /// + /// \brief stopRubberBand + /// Removes the rubber band from display when finished with. + void stopRubberBand(); protected: static const int DEFAULT_PIXELS_PER_TACT = 16; diff --git a/include/fft_helpers.h b/include/fft_helpers.h index 1fafb6b81..59805c400 100644 --- a/include/fft_helpers.h +++ b/include/fft_helpers.h @@ -26,7 +26,6 @@ #ifndef FFT_HELPERS_H #define FFT_HELPERS_H -#include "lmmsconfig.h" #include "export.h" #include diff --git a/include/lmms_basics.h b/include/lmms_basics.h index bdd72f4fa..ea02f77d1 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -78,9 +78,9 @@ struct typeInfo return 1; } - static inline bool isEqual( T _x, T _y ) + static inline bool isEqual( T x, T y ) { - return _x == _y; + return x == y; } static inline T absVal( T t ) @@ -97,13 +97,13 @@ inline float typeInfo::minEps() } template<> -inline bool typeInfo::isEqual( float _x, float _y ) +inline bool typeInfo::isEqual( float x, float y ) { - if( likely( _x == _y ) ) + if( x == y ) { return true; } - return absVal( _x - _y ) < minEps(); + return absVal( x - y ) < minEps(); } diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index ec3178d85..67e7ba3b4 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -497,6 +497,15 @@ bool MidiImport::readSMF( TrackContainer* tc ) } } + // Set channel 10 to drums as per General MIDI's orders + if( chs[9].hasNotes && chs[9].it_inst && chs[9].isSF2 ) + { + // AFAIK, 128 should be the standard bank for drums in SF2. + // If not, this has to be made configurable. + chs[9].it_inst->childModel( "bank" )->setValue( 128 ); + chs[9].it_inst->childModel( "patch" )->setValue( 0 ); + } + return true; } diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 9549f5ad1..6c7501c8b 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -22,9 +22,8 @@ * */ -#include - #include "AutomatableModel.h" + #include "AutomationPattern.h" #include "ControllerConnection.h" #include "lmms_math.h" @@ -75,7 +74,7 @@ AutomatableModel::~AutomatableModel() { delete m_controllerConnection; } - + m_valueBuffer.clear(); emit destroyed( id() ); @@ -171,7 +170,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString& //m_controllerConnection->setTargetName( displayName() ); } } - + // models can be stored as elements (port00) or attributes (port10): // // @@ -566,7 +565,7 @@ ValueBuffer * AutomatableModel::valueBuffer() } } AutomatableModel* lm = NULL; - if( m_hasLinkedModels ) + if( m_hasLinkedModels ) { lm = m_linkedModels.first(); } @@ -583,7 +582,7 @@ ValueBuffer * AutomatableModel::valueBuffer() m_hasSampleExactData = true; return &m_valueBuffer; } - + if( m_oldValue != val ) { m_valueBuffer.interpolate( m_oldValue, val ); @@ -592,7 +591,7 @@ ValueBuffer * AutomatableModel::valueBuffer() m_hasSampleExactData = true; return &m_valueBuffer; } - + // if we have no sample-exact source for a ValueBuffer, return NULL to signify that no data is available at the moment // in which case the recipient knows to use the static value() instead m_lastUpdatedPeriod = s_periodCounter; @@ -667,11 +666,11 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) { int s = ( *it )->startPosition(); int e = ( *it )->endPosition(); - if( s <= time && e >= time ) { patternsInRange += ( *it ); } + if( s <= time && e >= time ) { patternsInRange += ( *it ); } } - + AutomationPattern * latestPattern = NULL; - + if( ! patternsInRange.isEmpty() ) { // if there are more than one overlapping patterns, just use the first one because @@ -682,7 +681,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) // if we find no patterns at the exact miditime, we need to search for the last pattern before time and use that { int latestPosition = 0; - + for( QVector::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) { int e = ( *it )->endPosition(); @@ -693,7 +692,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) } } } - + if( latestPattern ) { // scale/fit the value appropriately and return it @@ -701,7 +700,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) const float scaled_value = scaledValue( value ); return fittedValue( scaled_value ); } - // if we still find no pattern, the value at that time is undefined so + // if we still find no pattern, the value at that time is undefined so // just return current value as the best we can do else return m_value; } diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index beb11bd2d..4c8791ee3 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -24,9 +24,8 @@ * */ -#include - #include "AutomationPattern.h" + #include "AutomationPatternView.h" #include "AutomationTrack.h" #include "ProjectJournal.h" @@ -192,7 +191,7 @@ const AutomatableModel * AutomationPattern::firstObject() const MidiTime AutomationPattern::length() const { if( m_timeMap.isEmpty() ) return 0; - timeMap::const_iterator it = m_timeMap.end(); + timeMap::const_iterator it = m_timeMap.end(); return MidiTime( qMax( MidiTime( (it-1).key() ).getTact() + 1, 1 ), 0 ); } @@ -412,7 +411,7 @@ void AutomationPattern::flipY( int min, int max ) { numPoints++; } - + for( int i = 0; i <= numPoints; i++ ) { @@ -501,7 +500,7 @@ void AutomationPattern::flipX( int length ) tempMap[newTime] = tempValue; } } - + m_timeMap.clear(); m_timeMap = tempMap; @@ -617,7 +616,7 @@ void AutomationPattern::processMidiTime( const MidiTime & time ) ( *it )->setAutomatedValue( val ); } - } + } } } else @@ -625,7 +624,7 @@ void AutomationPattern::processMidiTime( const MidiTime & time ) if( time >= 0 && ! m_objects.isEmpty() ) { const float value = static_cast( firstObject()->value() ); - if( value != m_lastRecordedValue ) + if( value != m_lastRecordedValue ) { putValue( time, value, true ); m_lastRecordedValue = value; @@ -692,7 +691,7 @@ QVector AutomationPattern::patternsForModel( const Automata l += Engine::getSong()->tracks(); l += Engine::getBBTrackContainer()->tracks(); l += Engine::getSong()->globalAutomationTrack(); - + // go through all tracks... for( TrackContainer::TrackList::ConstIterator it = l.begin(); it != l.end(); ++it ) { diff --git a/src/core/BBTrackContainer.cpp b/src/core/BBTrackContainer.cpp index 839e40994..d38cfdc00 100644 --- a/src/core/BBTrackContainer.cpp +++ b/src/core/BBTrackContainer.cpp @@ -2,7 +2,7 @@ * BBTrackContainer.cpp - model-component of BB-Editor * * Copyright (c) 2004-2014 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -25,8 +25,6 @@ #include "BBTrackContainer.h" #include "BBTrack.h" -#include "ComboBox.h" -#include "embed.h" #include "Engine.h" #include "Song.h" diff --git a/src/core/BandLimitedWave.cpp b/src/core/BandLimitedWave.cpp index 11b3790a5..de608ba1d 100644 --- a/src/core/BandLimitedWave.cpp +++ b/src/core/BandLimitedWave.cpp @@ -25,6 +25,7 @@ #include "BandLimitedWave.h" +#include "ConfigManager.h" WaveMipMap BandLimitedWave::s_waveforms[4] = { }; bool BandLimitedWave::s_wavesGenerated = false; @@ -62,7 +63,7 @@ void BandLimitedWave::generateWaves() { // don't generate if they already exist if( s_wavesGenerated ) return; - + int i; // set wavetable directory @@ -90,7 +91,7 @@ void BandLimitedWave::generateWaves() const int len = TLENS[i]; //const double om = 1.0 / len; double max = 0.0; - + for( int ph = 0; ph < len; ph++ ) { int harm = 1; @@ -115,7 +116,7 @@ void BandLimitedWave::generateWaves() } } } - + // square wave - BLSquare // check for file and use it if exists if( sqr_file.exists() ) @@ -132,7 +133,7 @@ void BandLimitedWave::generateWaves() const int len = TLENS[i]; //const double om = 1.0 / len; double max = 0.0; - + for( int ph = 0; ph < len; ph++ ) { int harm = 1; @@ -173,7 +174,7 @@ void BandLimitedWave::generateWaves() const int len = TLENS[i]; //const double om = 1.0 / len; double max = 0.0; - + for( int ph = 0; ph < len; ph++ ) { int harm = 1; @@ -184,7 +185,7 @@ void BandLimitedWave::generateWaves() hlen = static_cast( len ) / static_cast( harm ); const double amp = 1.0 / static_cast( harm * harm ); //const double a2 = cos( om * harm * F_2PI ); - s += amp * /*a2 **/ sin( ( static_cast( ph * harm ) / static_cast( len ) + + s += amp * /*a2 **/ sin( ( static_cast( ph * harm ) / static_cast( len ) + ( ( harm + 1 ) % 4 == 0 ? 0.5 : 0.0 ) ) * F_2PI ); harm += 2; } while( hlen > 2.0 ); @@ -199,7 +200,7 @@ void BandLimitedWave::generateWaves() } } } - + // moog saw wave - BLMoog // basically, just add in triangle + 270-phase saw if( moog_file.exists() ) @@ -214,7 +215,7 @@ void BandLimitedWave::generateWaves() for( i = 0; i <= MAXTBL; i++ ) { const int len = TLENS[i]; - + for( int ph = 0; ph < len; ph++ ) { const int sawph = ( ph + static_cast( len * 0.75 ) ) % len; @@ -224,7 +225,7 @@ void BandLimitedWave::generateWaves() } } } - + // set the generated flag so we don't load/generate them again needlessly s_wavesGenerated = true; @@ -232,14 +233,14 @@ void BandLimitedWave::generateWaves() // generate files, serialize mipmaps as QDataStreams and save them on disk // // normally these are now provided with LMMS as pre-generated so we don't have to do this, -// but I'm leaving the code here in case it's needed in the future +// but I'm leaving the code here in case it's needed in the future // (maybe we add more waveforms or change the generation code or mipmap format, etc.) /* -// if you want to generate the files, you need to set the filenames and paths here - +// if you want to generate the files, you need to set the filenames and paths here - // can't use the usual wavetable directory here as it can require permissions on -// some systems... +// some systems... QFile sawfile( "path-to-wavetables/saw.bin" ); QFile sqrfile( "path-to-wavetables/sqr.bin" ); diff --git a/src/core/BufferManager.cpp b/src/core/BufferManager.cpp index cb38d45e9..1f535443e 100644 --- a/src/core/BufferManager.cpp +++ b/src/core/BufferManager.cpp @@ -25,6 +25,10 @@ #include "BufferManager.h" +#include +#include + +#include "MemoryManager.h" sampleFrame ** BufferManager::s_available; QAtomicInt BufferManager::s_availableIndex = 0; @@ -41,7 +45,7 @@ void BufferManager::init( fpp_t framesPerPeriod ) int c = framesPerPeriod * BM_INITIAL_BUFFERS; sampleFrame * b = MM_ALLOC( sampleFrame, c ); - + for( int i = 0; i < BM_INITIAL_BUFFERS; ++i ) { s_available[ i ] = b; @@ -58,10 +62,10 @@ sampleFrame * BufferManager::acquire() { qFatal( "BufferManager: out of buffers" ); } - + int i = s_availableIndex.fetchAndAddOrdered( -1 ); sampleFrame * b = s_available[ i ]; - + //qDebug( "acquired buffer: %p - index %d", b, i ); return b; } @@ -79,7 +83,7 @@ void BufferManager::refresh() // non-threadsafe, hence it's called periodically { if( s_releasedIndex == 0 ) return; //qDebug( "refresh: %d buffers", int( s_releasedIndex ) ); - + int j = s_availableIndex; for( int i = 0; i < s_releasedIndex; ++i ) { @@ -101,7 +105,7 @@ void BufferManager::extend( int c ) int cc = c * Engine::mixer()->framesPerPeriod(); sampleFrame * b = MM_ALLOC( sampleFrame, cc ); - + for( int i = 0; i < c; ++i ) { s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = b; diff --git a/src/core/ControllerConnection.cpp b/src/core/ControllerConnection.cpp index 3c0266ab6..8b7040b50 100644 --- a/src/core/ControllerConnection.cpp +++ b/src/core/ControllerConnection.cpp @@ -1,5 +1,5 @@ /* - * ControllerConnection.cpp - implementation of class controller connection + * ControllerConnection.cpp - implementation of class controller connection * which handles the link between AutomatableModels and controllers * * Copyright (c) 2008 Paul Giblock @@ -26,12 +26,10 @@ #include #include -#include #include "Song.h" #include "Engine.h" -#include "Mixer.h" #include "ControllerConnection.h" @@ -123,7 +121,7 @@ void ControllerConnection::setController( Controller * _controller ) this, SIGNAL( valueChanged() ) ); } - m_ownsController = + m_ownsController = ( _controller->type() == Controller::MidiController ); // If we don't own the controller, allow deletion of controller @@ -150,8 +148,8 @@ inline void ControllerConnection::setTargetName( const QString & _name ) /* * A connection may not be finalized. This means, the connection should exist, * but the controller does not yet exist. This happens when loading. Even - * loading connections last won't help, since there can be connections BETWEEN - * controllers. So, we remember the controller-ID and use a dummyController + * loading connections last won't help, since there can be connections BETWEEN + * controllers. So, we remember the controller-ID and use a dummyController * instead. Once the song is loaded, finalizeConnections() connects to the proper controllers */ void ControllerConnection::finalizeConnections() diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 7bf47ed67..8db694367 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -37,14 +37,12 @@ #include "ConfigManager.h" #include "ProjectVersion.h" +#include "ProjectVersion.h" #include "SongEditor.h" #include "Effect.h" #include "lmmsversion.h" #include "base64.h" -// bbTCO::defaultColor() -#include "BBTrack.h" - DataFile::typeDescStruct @@ -127,14 +125,18 @@ DataFile::DataFile( const QString & _fileName ) : QFile inFile( _fileName ); if( !inFile.open( QIODevice::ReadOnly ) ) { - QMessageBox::critical( NULL, - SongEditor::tr( "Could not open file" ), - SongEditor::tr( "Could not open file %1. You probably " - "have no permissions to read this " - "file.\n Please make sure to have at " - "least read permissions to the file " - "and try again." ).arg( _fileName ) ); - return; + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Could not open file" ), + SongEditor::tr( "Could not open file %1. You probably " + "have no permissions to read this " + "file.\n Please make sure to have at " + "least read permissions to the file " + "and try again." ).arg( _fileName ) ); + } + + return; } loadData( inFile.readAll(), _fileName ); @@ -222,11 +224,15 @@ bool DataFile::writeFile( const QString& filename ) if( !outfile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) { - QMessageBox::critical( NULL, - SongEditor::tr( "Could not write file" ), - SongEditor::tr( "Could not open %1 for writing. You probably are not permitted to " - "write to this file. Please make sure you have write-access to " - "the file and try again." ).arg( fullName ) ); + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Could not write file" ), + SongEditor::tr( "Could not open %1 for writing. You probably are not permitted to " + "write to this file. Please make sure you have write-access to " + "the file and try again." ).arg( fullName ) ); + } + return false; } @@ -628,7 +634,7 @@ void DataFile::upgrade() el.setAttribute( "lp1pos", el.attribute( "lp1pos" ).toInt()*3 ); } - + } if( version < "0.4.0-20080607" ) @@ -768,12 +774,16 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) if( line >= 0 && col >= 0 ) { qWarning() << "at line" << line << "column" << errorMsg; - QMessageBox::critical( NULL, - SongEditor::tr( "Error in file" ), - SongEditor::tr( "The file %1 seems to contain " - "errors and therefore can't be " - "loaded." ). - arg( _sourceFile ) ); + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Error in file" ), + SongEditor::tr( "The file %1 seems to contain " + "errors and therefore can't be " + "loaded." ). + arg( _sourceFile ) ); + } + return; } } @@ -782,10 +792,37 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) m_type = type( root.attribute( "type" ) ); m_head = root.elementsByTagName( "head" ).item( 0 ).toElement(); - if( root.hasAttribute( "creatorversion" ) && - root.attribute( "creatorversion" ) != LMMS_VERSION ) + + if( root.hasAttribute( "creatorversion" ) ) { - upgrade(); + // compareType defaults to Build,so it doesn't have to be set here + ProjectVersion createdWith = root.attribute( "creatorversion" ); + ProjectVersion openedWith = LMMS_VERSION;; + + if ( createdWith != openedWith ) + { + // only one compareType needs to be set, and we can compare on one line because setCompareType returns ProjectVersion + if ( createdWith.setCompareType(Minor) != openedWith) + { + if( Engine::hasGUI() ) + { + QMessageBox::information( NULL, + SongEditor::tr( "Project Version Mismatch" ), + SongEditor::tr( + "This project was created with " + "LMMS version %1, but version %2 " + "is installed") + .arg( root.attribute( "creatorversion" ) ) + .arg( LMMS_VERSION ) ); + } + } + + // the upgrade needs to happen after the warning as it updates the project version. + if( createdWith.setCompareType(Build) < openedWith ) + { + upgrade(); + } + } } m_content = root.elementsByTagName( typeName( m_type ) ). diff --git a/src/core/DrumSynth.cpp b/src/core/DrumSynth.cpp index 305ed5ae1..8c732bb7d 100644 --- a/src/core/DrumSynth.cpp +++ b/src/core/DrumSynth.cpp @@ -3,7 +3,7 @@ * * Copyright (c) 1998-2000 Paul Kellett (mda-vst.com) * Copyright (c) 2007 Paul Giblock - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -25,7 +25,6 @@ #include "DrumSynth.h" -#include "lmmsconfig.h" #include #include @@ -71,13 +70,13 @@ float mem_t=1.0f, mem_o=1.0f, mem_n=1.0f, mem_b=1.0f, mem_tune=1.0f, mem_time=1. int DrumSynth::LongestEnv(void) { long e, eon, p; - float l=0.f; - + float l=0.f; + for(e=1; e<7; e++) //3 { eon = e - 1; if(eon>2) eon=eon-1; p = 0; - while (envpts[e][0][p + 1] >= 0.f) p++; + while (envpts[e][0][p + 1] >= 0.f) p++; envData[e][MAX] = envpts[e][0][p] * timestretch; if(chkOn[eon]==1) if(envData[e][MAX]>l) l=envData[e][MAX]; } @@ -88,7 +87,7 @@ int DrumSynth::LongestEnv(void) float DrumSynth::LoudestEnv(void) -{ +{ float loudest=0.f; int i=0; @@ -102,9 +101,9 @@ float DrumSynth::LoudestEnv(void) void DrumSynth::UpdateEnv(int e, long t) -{ +{ float endEnv, dT; - //0.2's added + //0.2's added envData[e][NEXTT] = envpts[e][0][(long)(envData[e][PNT] + 1.f)] * timestretch; //get next point if(envData[e][NEXTT] < 0) envData[e][NEXTT] = 442000 * timestretch; //if end point, hold envData[e][ENV] = envpts[e][1][(long)(envData[e][PNT] + 0.f)] * 0.01f; //this level @@ -122,14 +121,14 @@ void DrumSynth::GetEnv(int env, const char *sec, const char *key, const char *in int i=0, o=0, ep=0; GetPrivateProfileString(sec, key, "0,0 100,0", en, sizeof(en), ini); en[255]=0; //be safe! - + while(en[i]!=0) { - if(en[i] == ',') + if(en[i] == ',') { if(sscanf(s, "%f", &envpts[env][0][ep])==0) envpts[env][0][ep] = 0.f; o=0; - } + } else if(en[i] == ' ') { if(sscanf(s, "%f", &envpts[env][1][ep])==0) envpts[env][1][ep] = 0.f; @@ -148,7 +147,7 @@ void DrumSynth::GetEnv(int env, const char *sec, const char *key, const char *in float DrumSynth::waveform(float ph, int form) { float w; - + switch (form) { case 0: w = (float)sin(fmod(ph,TwoPi)); break; //sine @@ -157,15 +156,15 @@ float DrumSynth::waveform(float ph, int form) w = 0.6366197f * (float)fmod(ph,TwoPi) - 1.f; //tri if(w>1.f) w=2.f-w; break; case 3: w = ph - TwoPi * (float)(int)(ph / TwoPi); //saw - w = (0.3183098f * w) - 1.f; break; + w = (0.3183098f * w) - 1.f; break; default: w = (sin(fmod(ph,TwoPi))>0.0)? 1.f: -1.f; break; //square - } - + } + return w; } -int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file) +int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file) { ifstream is; bool inSection = false; @@ -190,12 +189,12 @@ int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const c } else if (!is.eof()) { is.getline(line, 200); - if (line[0] == '[') + if (line[0] == '[') break; k = strtok(line, " \t="); b = strtok(NULL, "\n\r\0"); - + if (k != 0 && strcasecmp(k, key)==0) { if (b==0) { len = 0; @@ -203,7 +202,7 @@ int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const c } else { k = (char *)(b + strlen(b)-1); - while ( (k>=b) && (*k==' ' || *k=='\t') ) + while ( (k>=b) && (*k==' ' || *k=='\t') ) --k; *(k+1) = '\0'; @@ -233,9 +232,9 @@ int DrumSynth::GetPrivateProfileInt(const char *sec, const char *key, int def, c int i=0; GetPrivateProfileString(sec, key, "", tmp, sizeof(tmp), file); - sscanf(tmp, "%d", &i); if(tmp[0]==0) i=def; - - return i; + sscanf(tmp, "%d", &i); if(tmp[0]==0) i=def; + + return i; } float DrumSynth::GetPrivateProfileFloat(const char *sec, const char *key, float def, const char *file) @@ -244,9 +243,9 @@ float DrumSynth::GetPrivateProfileFloat(const char *sec, const char *key, float float f=0.f; GetPrivateProfileString(sec, key, "", tmp, sizeof(tmp), file); - sscanf(tmp, "%f", &f); if(tmp[0]==0) f=def; + sscanf(tmp, "%f", &f); if(tmp[0]==0) f=def; - return f; + return f; } @@ -259,7 +258,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels { //input file char sec[32]; - char ver[32]; + char ver[32]; char comment[256]; int commentLen=0; @@ -268,11 +267,11 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels float x[3] = {0.f, 0.f, 0.f}; float MasterTune, randmax, randmax2; int MainFilter, HighPass; - + long NON, NT, TON, DiON, TDroop=0, DStep; float a, b=0.f, c=0.f, d=0.f, g, TT=0.f, TL, NL, F1, F2; float TphiStart=0.f, Tphi, TDroopRate, ddF, DAtten, DGain; - + long BON, BON2, BFStep, BFStep2, botmp; float BdF=0.f, BdF2=0.f, BPhi, BPhi2, BF, BF2, BQ, BQ2, BL, BL2; @@ -282,7 +281,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels float Oc0=0.0f, Oc1=0.0f, Oc2=0.0f; float MFfb, MFtmp, MFres, MFin=0.f, MFout=0.f; - float DownAve; + float DownAve; long DownStart, DownEnd, jj; @@ -297,22 +296,22 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels } //try to read version from input file - strcpy(sec, "General"); + strcpy(sec, "General"); GetPrivateProfileString(sec,"Version","",ver,sizeof(ver),dsfile); - ver[9]=0; + ver[9]=0; if(strcasecmp(ver, "DrumSynth") != 0) {return 0;} //input fail if(ver[11] != '1' && ver[11] != '2') {return 0;} //version fail - + //read master parameters GetPrivateProfileString(sec,"Comment","",comment,sizeof(comment),dsfile); while((comment[commentLen]!=0) && (commentLen<254)) commentLen++; if(commentLen==0) { comment[0]=32; comment[1]=0; commentLen=1;} comment[commentLen+1]=0; commentLen++; - if((commentLen % 2)==1) commentLen++; - + if((commentLen % 2)==1) commentLen++; + timestretch = .01f * mem_time * GetPrivateProfileFloat(sec,"Stretch",100.0,dsfile); - if(timestretch<0.2f) timestretch=0.2f; + if(timestretch<0.2f) timestretch=0.2f; if(timestretch>10.f) timestretch=10.f; DGain = 1.0f; //leave this here! @@ -320,35 +319,35 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels MasterTune = GetPrivateProfileFloat(sec,"Tuning",0.0,dsfile); MasterTune = (float)powf(1.0594631f, MasterTune + mem_tune); - MainFilter = 2 * GetPrivateProfileInt(sec,"Filter",0,dsfile); + MainFilter = 2 * GetPrivateProfileInt(sec,"Filter",0,dsfile); MFres = 0.0101f * GetPrivateProfileFloat(sec,"Resonance",0.0,dsfile); MFres = (float)powf(MFres, 0.5f); - + HighPass = GetPrivateProfileInt(sec,"HighPass",0,dsfile); GetEnv(7, sec, "FilterEnv", dsfile); - + //read noise parameters strcpy(sec, "Noise"); chkOn[1] = GetPrivateProfileInt(sec,"On",0,dsfile); - sliLev[1] = GetPrivateProfileInt(sec,"Level",0,dsfile); - NT = GetPrivateProfileInt(sec,"Slope",0,dsfile); + sliLev[1] = GetPrivateProfileInt(sec,"Level",0,dsfile); + NT = GetPrivateProfileInt(sec,"Slope",0,dsfile); GetEnv(2, sec, "Envelope", dsfile); - NON = chkOn[1]; + NON = chkOn[1]; NL = (float)(sliLev[1] * sliLev[1]) * mem_n; if(NT<0) { a = 1.f + (NT / 105.f); d = -NT / 105.f; g = (1.f + 0.0005f * NT * NT) * NL; } else { a = 1.f; b = -NT / 50.f; c = (float)fabs((float)NT) / 100.f; g = NL; } - - //if(GetPrivateProfileInt(sec,"FixedSeq",0,dsfile)!=0) + + //if(GetPrivateProfileInt(sec,"FixedSeq",0,dsfile)!=0) //srand(1); //fixed random sequence - + //read tone parameters strcpy(sec, "Tone"); chkOn[0] = GetPrivateProfileInt(sec,"On",0,dsfile); TON = chkOn[0]; - sliLev[0] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[0] = GetPrivateProfileInt(sec,"Level",128,dsfile); TL = (float)(sliLev[0] * sliLev[0]) * mem_t; GetEnv(1, sec, "Envelope", dsfile); F1 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F1",200.0,dsfile) / Fs; @@ -364,13 +363,13 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels ddF = F1 - F2; } else ddF = F2-F1; - + Tphi = GetPrivateProfileFloat(sec,"Phase",90.f,dsfile) / 57.29578f; //degrees>radians //read overtone parameters strcpy(sec, "Overtones"); chkOn[2] = GetPrivateProfileInt(sec,"On",0,dsfile); OON = chkOn[2]; - sliLev[2] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[2] = GetPrivateProfileInt(sec,"Level",128,dsfile); OL = (float)(sliLev[2] * sliLev[2]) * mem_o; GetEnv(3, sec, "Envelope1", dsfile); GetEnv(4, sec, "Envelope2", dsfile); @@ -381,11 +380,11 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels OW2 = GetPrivateProfileInt(sec,"Wave2",0,dsfile); OBal2 = (float)GetPrivateProfileInt(sec,"Param",50,dsfile); ODrive = (float)powf(OBal2, 3.0f) / (float)powf(50.0f, 3.0f); - OBal2 *= 0.01f; + OBal2 *= 0.01f; OBal1 = 1.f - OBal2; - Ophi1 = Tphi; + Ophi1 = Tphi; Ophi2 = Tphi; - if(MainFilter==0) + if(MainFilter==0) MainFilter = GetPrivateProfileInt(sec,"Filter",0,dsfile); if((GetPrivateProfileInt(sec,"Track1",0,dsfile)==1) && (TON==1)) { OF1Sync = 1; OF1 = OF1 / F1; } @@ -403,28 +402,28 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels //read noise band parameters strcpy(sec, "NoiseBand"); chkOn[3] = GetPrivateProfileInt(sec,"On",0,dsfile); BON = chkOn[3]; - sliLev[3] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[3] = GetPrivateProfileInt(sec,"Level",128,dsfile); BL = (float)(sliLev[3] * sliLev[3]) * mem_b; BF = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F",1000.0,dsfile) / Fs; BPhi = TwoPi / 8.f; GetEnv(5, sec, "Envelope", dsfile); - BFStep = GetPrivateProfileInt(sec,"dF",50,dsfile); - BQ = (float)BFStep; + BFStep = GetPrivateProfileInt(sec,"dF",50,dsfile); + BQ = (float)BFStep; BQ = BQ * BQ / (10000.f-6600.f*((float)sqrt(BF)-0.19f)); BFStep = 1 + (int)((40.f - (BFStep / 2.5f)) / (BQ + 1.f + (1.f * BF))); strcpy(sec, "NoiseBand2"); chkOn[4] = GetPrivateProfileInt(sec,"On",0,dsfile); BON2 = chkOn[4]; - sliLev[4] = GetPrivateProfileInt(sec,"Level",128,dsfile); + sliLev[4] = GetPrivateProfileInt(sec,"Level",128,dsfile); BL2 = (float)(sliLev[4] * sliLev[4]) * mem_b; BF2 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F",1000.0,dsfile) / Fs; BPhi2 = TwoPi / 8.f; GetEnv(6, sec, "Envelope", dsfile); - BFStep2 = GetPrivateProfileInt(sec,"dF",50,dsfile); + BFStep2 = GetPrivateProfileInt(sec,"dF",50,dsfile); BQ2 = (float)BFStep2; BQ2 = BQ2 * BQ2 / (10000.f-6600.f*((float)sqrt(BF2)-0.19f)); BFStep2 = 1 + (int)((40 - (BFStep2 / 2.5)) / (BQ2 + 1 + (1 * BF2))); - + //read distortion parameters strcpy(sec, "Distortion"); chkOn[5] = GetPrivateProfileInt(sec,"On",0,dsfile); DiON = chkOn[5]; @@ -434,14 +433,14 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels clippoint = 32700; DAtten = 1.0f; - if(DiON==1) + if(DiON==1) { - DAtten = DGain * (short)LoudestEnv(); - if(DAtten>32700) clippoint=32700; else clippoint=(short)DAtten; + DAtten = DGain * (short)LoudestEnv(); + if(DAtten>32700) clippoint=32700; else clippoint=(short)DAtten; DAtten = (float)powf(2.0, 2.0 * GetPrivateProfileInt(sec,"Bits",0,dsfile)); DGain = DAtten * DGain * (float)powf(10.0, 0.05 * GetPrivateProfileInt(sec,"Clipping",0,dsfile)); } - + //prepare envelopes randmax = 1.f / RAND_MAX; randmax2 = 2.f * randmax; for (i=1;i<8;i++) { envData[i][NEXTT]=0; envData[i][PNT]=0; } @@ -473,7 +472,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels //write WAV header WH.riff = 0x46464952; - WH.riffLength = 36 + (2 * Length) + 44 + commentLen; + WH.riffLength = 36 + (2 * Length) + 44 + commentLen; WH.wave = 0x45564157; WH.fmt = 0x20746D66; WH.waveLength = 16; @@ -503,7 +502,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels else UpdateEnv(2, t); x[2] = x[1]; x[1] = x[0]; - x[0] = (randmax2 * (float)rand()) - 1.f; + x[0] = (randmax2 * (float)rand()) - 1.f; TT = a * x[0] + b * x[1] + c * x[2] + d * TT; DF[t - tpos] = TT * g * envData[2][ENV]; } @@ -512,7 +511,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels else { for(j=0; j<1200; j++) DF[j]=0.f; } - + if(TON==1) //tone { TphiStart = Tphi; @@ -520,16 +519,16 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels { for(t=tpos; t<=tplus; t++) phi[t - tpos] = F2 + (ddF * (float)exp(t * TDroopRate)); - } + } else { for(t=tpos; t<=tplus; t++) phi[t - tpos] = F1 + (t / envData[1][MAX]) * ddF; - } + } for(t=tpos; t<=tplus; t++) { totmp = t - tpos; - if(t < envData[1][NEXTT]) + if(t < envData[1][NEXTT]) envData[1][ENV] = envData[1][ENV] + envData[1][dENV]; else UpdateEnv(1, t); Tphi = Tphi + phi[totmp]; @@ -538,7 +537,7 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels if(t>=envData[1][MAX]) TON=0; } else for(j=0; j<1200; j++) phi[j]=F2; //for overtone sync - + if(BON==1) //noise band 1 { for(t=tpos; t<=tplus; t++) @@ -580,8 +579,8 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels { if(t>=envData[3][MAX]) //wait for OT2 { - envData[3][ENV] = 0; - envData[3][dENV] = 0; + envData[3][ENV] = 0; + envData[3][dENV] = 0; envData[3][NEXTT] = 999999; } else UpdateEnv(3, t); @@ -610,12 +609,12 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels Ot = OBal1 * envData[3][ENV] * waveform(Ophi1, OW1); Ot = OL * (Ot + OBal2 * envData[4][ENV] * waveform(Ophi2, OW2)); break; - + case 1: //FM Ot = ODrive * envData[4][ENV] * waveform(Ophi2, OW2); Ot = OL * envData[3][ENV] * waveform(Ophi1 + Ot, OW1); break; - + case 2: //RM Ot = (1 - ODrive / 8) + (((ODrive / 8) * envData[4][ENV]) * waveform(Ophi2, OW2)); Ot = OL * envData[3][ENV] * waveform(Ophi1, OW1) * Ot; @@ -625,10 +624,10 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels for(j=0; j<6; j++) { Oc[j][0] += 1.0f; - + if(Oc[j][0]>Oc[j][1]) - { - Oc[j][0] -= Oc[j][1]; + { + Oc[j][0] -= Oc[j][1]; Ot = OL * envData[3][ENV]; } } @@ -639,8 +638,8 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels Ot = Oc1; break; } - } - + } + if(MainFilter==1) //filter overtones { if(t0.2f) MFfb = 1.001f - (float)powf(10.0f, MFtmp - 1); else - MFfb = 0.999f - 0.7824f * MFtmp; - - MFtmp = Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); + MFfb = 0.999f - 0.7824f * MFtmp; + + MFtmp = Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); MFin = MFfb * (MFin - MFtmp) + MFtmp; MFout = MFfb * (MFout - MFin) + MFin; @@ -669,48 +668,48 @@ int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels if(MFtmp >0.2f) MFfb = 1.001f - (float)powf(10.0f, MFtmp - 1); else - MFfb = 0.999f - 0.7824f * MFtmp; - - MFtmp = DF[t - tpos] + Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); + MFfb = 0.999f - 0.7824f * MFtmp; + + MFtmp = DF[t - tpos] + Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout); MFin = MFfb * (MFin - MFtmp) + MFtmp; MFout = MFfb * (MFout - MFin) + MFin; - + DF[t - tpos] = MFout - (HighPass * (DF[t - tpos] + Ot)); } // PG: Ot is uninitialized else DF[t - tpos] = DF[t - tpos] + Ot; //no filter } - + if(DiON==1) //bit resolution { for(j=0; j<1200; j++) DF[j] = DGain * (int)(DF[j] / DAtten); - + for(j=0; j<1200; j+=DStep) //downsampling { DownAve = 0; DownStart = j; DownEnd = j + DStep - 1; - for(jj = DownStart; jj<=DownEnd; jj++) + for(jj = DownStart; jj<=DownEnd; jj++) DownAve = DownAve + DF[jj]; DownAve = DownAve / DStep; - for(jj = DownStart; jj<=DownEnd; jj++) + for(jj = DownStart; jj<=DownEnd; jj++) DF[jj] = DownAve; - } + } } else for(j=0; j<1200; j++) DF[j] *= DGain; - + for(j = 0; j<1200; j++) //clipping + output { if(DF[j] > clippoint) wave[wavewords++] = clippoint; - else if(DF[j] < -clippoint) + else if(DF[j] < -clippoint) wave[wavewords++] = -clippoint; - else + else wave[wavewords++] = (short)DF[j]; for (int c = 1; c < channels; c++) { - wave[wavewords] = wave[wavewords-1]; + wave[wavewords] = wave[wavewords-1]; wavewords++; } } diff --git a/src/core/EffectChain.cpp b/src/core/EffectChain.cpp index 5890566a3..f310f94dc 100644 --- a/src/core/EffectChain.cpp +++ b/src/core/EffectChain.cpp @@ -29,7 +29,6 @@ #include "EffectChain.h" #include "Effect.h" #include "Engine.h" -#include "debug.h" #include "DummyEffect.h" #include "MixHelpers.h" #include "Song.h" @@ -148,7 +147,7 @@ void EffectChain::moveDown( Effect * _effect ) if( _effect != m_effects.last() ) { int i = 0; - for( EffectList::Iterator it = m_effects.begin(); + for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); it++, i++ ) { if( *it == _effect ) @@ -156,10 +155,10 @@ void EffectChain::moveDown( Effect * _effect ) break; } } - + Effect * temp = m_effects[i + 1]; m_effects[i + 1] = _effect; - m_effects[i] = temp; + m_effects[i] = temp; } } @@ -171,7 +170,7 @@ void EffectChain::moveUp( Effect * _effect ) if( _effect != m_effects.first() ) { int i = 0; - for( EffectList::Iterator it = m_effects.begin(); + for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); it++, i++ ) { if( *it == _effect ) @@ -179,10 +178,10 @@ void EffectChain::moveUp( Effect * _effect ) break; } } - + Effect * temp = m_effects[i - 1]; m_effects[i - 1] = _effect; - m_effects[i] = temp; + m_effects[i] = temp; } } @@ -240,8 +239,8 @@ void EffectChain::startRunning() { return; } - - for( EffectList::Iterator it = m_effects.begin(); + + for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); it++ ) { ( *it )->startRunning(); diff --git a/src/core/Engine.cpp b/src/core/Engine.cpp index b11ad1e47..5730e977e 100644 --- a/src/core/Engine.cpp +++ b/src/core/Engine.cpp @@ -27,13 +27,10 @@ #include "BBTrackContainer.h" #include "ConfigManager.h" #include "FxMixer.h" -#include "InstrumentTrack.h" #include "Ladspa2LMMS.h" #include "Mixer.h" -#include "Pattern.h" #include "PresetPreviewPlayHandle.h" #include "ProjectJournal.h" -#include "ProjectNotes.h" #include "Plugin.h" #include "Song.h" #include "BandLimitedWave.h" diff --git a/src/core/EnvelopeAndLfoParameters.cpp b/src/core/EnvelopeAndLfoParameters.cpp index 90f6747f0..271bfd6f4 100644 --- a/src/core/EnvelopeAndLfoParameters.cpp +++ b/src/core/EnvelopeAndLfoParameters.cpp @@ -25,7 +25,6 @@ #include #include "EnvelopeAndLfoParameters.h" -#include "debug.h" #include "Engine.h" #include "Mixer.h" #include "Oscillator.h" @@ -379,7 +378,7 @@ void EnvelopeAndLfoParameters::loadSettings( const QDomElement & _this ) with 4.15 file format*/ if( _this.hasAttribute( "sus" ) ) - { + { m_sustainModel.loadSettings( _this, "sus" ); m_sustainModel.setValue( 1.0 - m_sustainModel.value() ); } @@ -392,7 +391,7 @@ void EnvelopeAndLfoParameters::loadSettings( const QDomElement & _this ) ( TempoSyncKnob::TtempoSyncMode ) _this.attribute( "lfosyncmode" ).toInt() ); }*/ - + m_userWave.setAudioFile( _this.attribute( "userwavefile" ) ); updateSampleVars(); diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index e6d1767ff..5a2c8a272 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -27,7 +27,6 @@ #include "FxMixer.h" #include "MixerWorkerThread.h" #include "MixHelpers.h" -#include "Effect.h" #include "Song.h" #include "InstrumentTrack.h" @@ -530,7 +529,10 @@ FloatModel * FxMixer::channelSendModel( fx_ch_t fromChannel, fx_ch_t toChannel ) void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch ) { - if( m_fxChannels[_ch]->m_muteModel.value() == false ) + // The first check is for the case where the last fxchannel was deleted but + // there was a race condition where it had to be processed. + if( _ch < m_fxChannels.size() && + m_fxChannels[_ch]->m_muteModel.value() == false ) { m_fxChannels[_ch]->m_lock.lock(); MixHelpers::add( m_fxChannels[_ch]->m_buffer, _buf, Engine::mixer()->framesPerPeriod() ); diff --git a/src/core/Instrument.cpp b/src/core/Instrument.cpp index f8b04fdb5..b4bf40bd1 100644 --- a/src/core/Instrument.cpp +++ b/src/core/Instrument.cpp @@ -26,7 +26,6 @@ #include "InstrumentTrack.h" #include "DummyInstrument.h" #include "NotePlayHandle.h" -#include "embed.h" #include "Engine.h" diff --git a/src/core/JournallingObject.cpp b/src/core/JournallingObject.cpp index 804483580..4c3163f0c 100644 --- a/src/core/JournallingObject.cpp +++ b/src/core/JournallingObject.cpp @@ -29,7 +29,6 @@ #include "JournallingObject.h" #include "AutomatableModel.h" #include "ProjectJournal.h" -#include "base64.h" #include "Engine.h" @@ -70,7 +69,7 @@ void JournallingObject::addJournalCheckPoint() QDomElement JournallingObject::saveState( QDomDocument & _doc, QDomElement & _parent ) { - if( isJournalling() ) + if( isJournalling() ) { QDomElement _this = SerializingObject::saveState( _doc, _parent ); diff --git a/src/core/LfoController.cpp b/src/core/LfoController.cpp index 5d77ce06a..f7c65a752 100644 --- a/src/core/LfoController.cpp +++ b/src/core/LfoController.cpp @@ -23,17 +23,14 @@ * */ -#include #include #include -#include #include "Song.h" #include "Engine.h" #include "Mixer.h" #include "LfoController.h" -#include "ControllerDialog.h" #include "lmms_math.h" @@ -47,7 +44,7 @@ LfoController::LfoController( Model * _parent ) : this, tr( "Oscillator waveform" ) ), m_multiplierModel( 0, 0, 2, this, tr( "Frequency Multiplier" ) ), m_duration( 1000 ), - m_phaseOffset( 0 ), + m_phaseOffset( 0 ), m_currentPhase( 0 ), m_sampleFunction( &Oscillator::sinSample ), m_userDefSampleBuffer( new SampleBuffer ) @@ -55,19 +52,19 @@ LfoController::LfoController( Model * _parent ) : setSampleExact( true ); connect( &m_waveModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleFunction() ) ); - + connect( &m_speedModel, SIGNAL( dataChanged() ), this, SLOT( updateDuration() ) ); connect( &m_multiplierModel, SIGNAL( dataChanged() ), this, SLOT( updateDuration() ) ); - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), + connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateDuration() ) ); - + connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), this, SLOT( updatePhase() ) ); connect( Engine::getSong(), SIGNAL( playbackPositionChanged() ), this, SLOT( updatePhase() ) ); - + updateDuration(); } @@ -88,12 +85,12 @@ LfoController::~LfoController() void LfoController::updateValueBuffer() { - m_phaseOffset = m_phaseModel.value() / 360.0; - float * values = m_valueBuffer.values(); + m_phaseOffset = m_phaseModel.value() / 360.0; + float * values = m_valueBuffer.values(); float phase = m_currentPhase + m_phaseOffset; // roll phase up until we're in sync with period counter - m_bufferLastUpdated++; + m_bufferLastUpdated++; if( m_bufferLastUpdated < s_periods ) { int diff = s_periods - m_bufferLastUpdated; @@ -103,16 +100,16 @@ void LfoController::updateValueBuffer() for( int i = 0; i < m_valueBuffer.length(); i++ ) - { - const float currentSample = m_sampleFunction != NULL + { + const float currentSample = m_sampleFunction != NULL ? m_sampleFunction( phase ) : m_userDefSampleBuffer->userWaveSample( phase ); - + values[i] = qBound( 0.0f, m_baseModel.value() + ( m_amountModel.value() * currentSample / 2.0f ), 1.0f ); phase += 1.0 / m_duration; } - + m_currentPhase = absFraction( phase - m_phaseOffset ); } @@ -141,7 +138,7 @@ void LfoController::updateDuration() default: break; } - + m_duration = newDurationF; } diff --git a/src/core/MemoryManager.cpp b/src/core/MemoryManager.cpp index 21cdf01ba..7366aa234 100644 --- a/src/core/MemoryManager.cpp +++ b/src/core/MemoryManager.cpp @@ -26,6 +26,7 @@ #include "MemoryManager.h" #include +#include #include diff --git a/src/core/MixHelpers.cpp b/src/core/MixHelpers.cpp index 513dd40d9..22065c967 100644 --- a/src/core/MixHelpers.cpp +++ b/src/core/MixHelpers.cpp @@ -22,8 +22,8 @@ * */ -#include "lmms_math.h" #include "MixHelpers.h" +#include "lmms_math.h" #include "ValueBuffer.h" diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 6f0b9557a..845abbf93 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -22,18 +22,14 @@ * */ -#include - #include "Mixer.h" + +#include "AudioPort.h" #include "FxMixer.h" -#include "MixHelpers.h" #include "MixerWorkerThread.h" #include "Song.h" -#include "templates.h" #include "EnvelopeAndLfoParameters.h" #include "NotePlayHandle.h" -#include "InstrumentTrack.h" -#include "debug.h" #include "Engine.h" #include "ConfigManager.h" #include "SamplePlayHandle.h" @@ -292,7 +288,7 @@ void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) f_cnt_t frames = m_inputBufferFrames[ m_inputBufferWrite ]; int size = m_inputBufferSize[ m_inputBufferWrite ]; sampleFrame * buf = m_inputBuffer[ m_inputBufferWrite ]; - + if( frames + _frames > size ) { size = qMax( size * 2, frames + _frames ); @@ -305,10 +301,10 @@ void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) buf = ab; } - + memcpy( &buf[ frames ], _ab, _frames * sizeof( sampleFrame ) ); m_inputBufferFrames[ m_inputBufferWrite ] += _frames; - + unlockInputFrames(); } @@ -359,7 +355,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer() if( it != m_playHandles.end() ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); - if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } @@ -415,7 +411,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer() if( ( *it )->isFinished() ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); - if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } @@ -446,7 +442,7 @@ const surroundSampleFrame * Mixer::renderNextBuffer() EnvelopeAndLfoParameters::instances()->trigger(); Controller::triggerFrameCounter(); AutomatableModel::incrementPeriodCounter(); - + // refresh buffer pool BufferManager::refresh(); @@ -639,7 +635,7 @@ bool Mixer::addPlayHandle( PlayHandle* handle ) return true; } - if( handle->type() == PlayHandle::TypeNotePlayHandle ) + if( handle->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*)handle ); } @@ -664,7 +660,7 @@ void Mixer::removePlayHandle( PlayHandle * _ph ) if( it != m_playHandles.end() ) { m_playHandles.erase( it ); - if( _ph->type() == PlayHandle::TypeNotePlayHandle ) + if( _ph->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) _ph ); } @@ -690,7 +686,7 @@ void Mixer::removePlayHandles( Track * _track, bool removeIPHs ) if( ( *it )->isFromTrack( _track ) && ( removeIPHs || ( *it )->type() != PlayHandle::TypeInstrumentPlayHandle ) ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); - if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } @@ -942,8 +938,8 @@ void Mixer::fifoWriter::run() #ifdef __SSE__ /* FTZ flag */ _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); -#endif - +#endif + #if 0 #ifdef LMMS_BUILD_LINUX #ifdef LMMS_HAVE_SCHED_H diff --git a/src/core/MixerWorkerThread.cpp b/src/core/MixerWorkerThread.cpp index 5a9ca166c..ef011f55f 100644 --- a/src/core/MixerWorkerThread.cpp +++ b/src/core/MixerWorkerThread.cpp @@ -23,8 +23,18 @@ */ #include "MixerWorkerThread.h" -#include "Engine.h" +#include +#include +#include "ThreadableJob.h" +#include "Mixer.h" + +#ifdef __SSE__ +#include +#endif +#ifdef __SSE3__ +#include +#endif MixerWorkerThread::JobQueue MixerWorkerThread::globalJobQueue; QWaitCondition * MixerWorkerThread::queueReadyWaitCond = NULL; @@ -157,7 +167,7 @@ void MixerWorkerThread::run() #ifdef __SSE__ /* FTZ flag */ _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); -#endif +#endif QMutex m; while( m_quit == false ) { diff --git a/src/core/Note.cpp b/src/core/Note.cpp index b973bb4e9..ed41abea8 100644 --- a/src/core/Note.cpp +++ b/src/core/Note.cpp @@ -68,7 +68,7 @@ Note::Note( const Note & note ) : m_selected( note.m_selected ), m_oldKey( note.m_oldKey ), m_oldPos( note.m_oldPos ), - m_oldLength( note.m_oldLength ), + m_oldLength( note.m_oldLength ), m_isPlaying( note.m_isPlaying ), m_key( note.m_key), m_volume( note.m_volume ), diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 19ec0517a..be5a38295 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -25,7 +25,6 @@ #include "NotePlayHandle.h" #include "BasicFilters.h" -#include "ConfigManager.h" #include "DetuningHelper.h" #include "InstrumentSoundShaping.h" #include "InstrumentTrack.h" @@ -93,14 +92,14 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, parent->m_hadChildren = true; m_bbTrack = parent->m_bbTrack; - + parent->setUsesBuffer( false ); } updateFrequency(); setFrames( _frames ); - + // inform attached components about new MIDI note (used for recording in Piano Roll) if( m_origin == OriginMidiInput ) { @@ -114,7 +113,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, // send MidiNoteOn event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ), - MidiTime::fromFrames( offset(), Engine::framesPerTick() ), + MidiTime::fromFrames( offset(), Engine::framesPerTick() ), offset() ); } @@ -122,9 +121,9 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, { setUsesBuffer( false ); } - + setAudioPort( instrumentTrack->audioPort() ); - + unlock(); } @@ -133,7 +132,7 @@ void NotePlayHandle::done() { lock(); noteOff( 0 ); - + if( hasParent() == false ) { delete m_baseDetuning; @@ -157,7 +156,7 @@ void NotePlayHandle::done() m_subNotes.clear(); delete m_filter; - + if( buffer() ) releaseBuffer(); unlock(); @@ -212,7 +211,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) setOffset( offset() - Engine::mixer()->framesPerPeriod() ); return; } - + lock(); if( m_frequencyNeedsUpdate ) { @@ -220,7 +219,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) } // number of frames that can be played this period - f_cnt_t framesThisPeriod = m_totalFramesPlayed == 0 + f_cnt_t framesThisPeriod = m_totalFramesPlayed == 0 ? Engine::mixer()->framesPerPeriod() - offset() : Engine::mixer()->framesPerPeriod(); @@ -386,7 +385,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s ) // send MidiNoteOff event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ), - MidiTime::fromFrames( _s, Engine::framesPerTick() ), + MidiTime::fromFrames( _s, Engine::framesPerTick() ), _s ); } @@ -597,7 +596,7 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac s_mutex.lockForRead(); NotePlayHandle * nph = s_available[ s_availableIndex.fetchAndAddOrdered( -1 ) ]; s_mutex.unlock(); - + new( (void*)nph ) NotePlayHandle( instrumentTrack, offset, frames, noteToPlay, parent, midiEventChannel, origin ); return nph; } @@ -618,7 +617,7 @@ void NotePlayHandleManager::extend( int c ) NotePlayHandle ** tmp = MM_ALLOC( NotePlayHandle*, s_size ); MM_FREE( s_available ); s_available = tmp; - + NotePlayHandle * n = MM_ALLOC( NotePlayHandle, c ); for( int i=0; i < c; ++i ) diff --git a/src/core/PeakController.cpp b/src/core/PeakController.cpp index c8702f937..2d92cff05 100644 --- a/src/core/PeakController.cpp +++ b/src/core/PeakController.cpp @@ -23,24 +23,20 @@ * */ +#include "PeakController.h" + #include #include #include -#include #include - -#include "Song.h" #include "Engine.h" #include "Mixer.h" -#include "PeakController.h" #include "EffectChain.h" -#include "ControllerDialog.h" #include "plugins/peak_controller_effect/peak_controller_effect.h" #include "PresetPreviewPlayHandle.h" -#include "lmms_math.h" -#include "interpolation.h" +class ControllerDialog; PeakControllerEffectVector PeakController::s_effects; int PeakController::m_getCount; @@ -48,7 +44,7 @@ int PeakController::m_loadCount; bool PeakController::m_buggedFile; -PeakController::PeakController( Model * _parent, +PeakController::PeakController( Model * _parent, PeakControllerEffect * _peak_effect ) : Controller( Controller::PeakController, _parent, tr( "Peak Controller" ) ), m_peakEffect( _peak_effect ), @@ -99,7 +95,7 @@ void PeakController::updateValueBuffer() { const f_cnt_t frames = Engine::mixer()->framesPerPeriod(); float * values = m_valueBuffer.values(); - + for( f_cnt_t f = 0; f < frames; ++f ) { const float diff = ( targetSample - m_currentSample ); diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 3bd0da7f7..d7f55b6e7 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -116,7 +116,7 @@ Song::Song() : /* connect( &m_masterPitchModel, SIGNAL( dataChanged() ), this, SLOT( masterPitchChanged() ) );*/ - qRegisterMetaType( "note" ); + qRegisterMetaType( "Note" ); setType( SongContainer ); } diff --git a/src/core/Track.cpp b/src/core/Track.cpp index dd003a6f2..4f5440af0 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -49,6 +49,7 @@ #include "AutomationPattern.h" #include "AutomationTrack.h" +#include "AutomationEditor.h" #include "BBEditor.h" #include "BBTrack.h" #include "BBTrackContainer.h" @@ -207,6 +208,8 @@ void TrackContentObject::paste() restoreState( *( Clipboard::getContent( nodeName() ) ) ); movePosition( pos ); } + AutomationPattern::resolveAllIDs(); + GuiApplication::instance()->automationEditor()->m_editor->updateAfterPatternChange(); } @@ -1436,6 +1439,7 @@ void TrackContentWidget::mousePressEvent( QMouseEvent * me ) else if( me->button() == Qt::LeftButton && !m_trackView->trackContainerView()->fixedTCOs() ) { + getTrack()->addJournalCheckPoint(); const MidiTime pos = getPosition( me->x() ).getTact() * MidiTime::ticksPerTact(); TrackContentObject * tco = getTrack()->createTCO( pos ); @@ -1705,29 +1709,6 @@ void TrackOperationsWidget::clearTrack() -/*! \brief Create and assign a new FX Channel for this track */ -void TrackOperationsWidget::createFxLine() -{ - int channelIndex = gui->fxMixerView()->addNewChannel(); - - Engine::fxMixer()->effectChannel( channelIndex )->m_name = m_trackView->getTrack()->name(); - - assignFxLine(channelIndex); -} - - - -/*! \brief Assign a specific FX Channel for this track */ -void TrackOperationsWidget::assignFxLine(int channelIndex) -{ - Track * track = m_trackView->getTrack(); - dynamic_cast( track )->effectChannelModel()->setValue( channelIndex ); - - gui->fxMixerView()->setCurrentFxLine( channelIndex ); -} - - - /*! \brief Remove this track from the track list * */ @@ -1764,31 +1745,8 @@ void TrackOperationsWidget::updateMenu() } if( InstrumentTrackView * trackView = dynamic_cast( m_trackView ) ) { - int channelIndex = trackView->model()->effectChannelModel()->value(); - - FxChannel * fxChannel = Engine::fxMixer()->effectChannel( channelIndex ); - - QMenu * fxMenu = new QMenu( tr( "FX %1: %2" ).arg( channelIndex ).arg( fxChannel->m_name ), toMenu ); - QSignalMapper * fxMenuSignalMapper = new QSignalMapper(this); - - fxMenu->addAction("Assign to new FX Channel" , this, SLOT( createFxLine() ) ); - fxMenu->addSeparator(); - - - for (int i = 0; i < Engine::fxMixer()->fxChannels().size(); ++i) - { - FxChannel * currentChannel = Engine::fxMixer()->fxChannels()[i]; - - if ( currentChannel != fxChannel ) - { - QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); - QAction * action = fxMenu->addAction( label, fxMenuSignalMapper, SLOT( map() ) ); - fxMenuSignalMapper->setMapping(action, currentChannel->m_channelIndex); - } - } - + QMenu *fxMenu = trackView->createFxMenu( tr( "FX %1: %2" ), tr( "Assign to new FX Channel" )); toMenu->addMenu(fxMenu); - connect(fxMenuSignalMapper, SIGNAL(mapped(int)), this, SLOT(assignFxLine(int))); toMenu->addSeparator(); toMenu->addMenu( trackView->midiMenu() ); @@ -2610,7 +2568,11 @@ void TrackView::mousePressEvent( QMouseEvent * me ) } - if( m_trackContainerView->allowRubberband() == true ) + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal ) { QWidget::mousePressEvent( me ); } @@ -2664,8 +2626,11 @@ void TrackView::mousePressEvent( QMouseEvent * me ) */ void TrackView::mouseMoveEvent( QMouseEvent * me ) { - - if( m_trackContainerView->allowRubberband() == true ) + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal ) { QWidget::mouseMoveEvent( me ); } diff --git a/src/core/base64.cpp b/src/core/base64.cpp index 08adc9d46..0479d468b 100644 --- a/src/core/base64.cpp +++ b/src/core/base64.cpp @@ -3,7 +3,7 @@ * to/from base64 * * Copyright (c) 2006-2008 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -26,7 +26,6 @@ #include "base64.h" -#include "lmms_basics.h" #include #include @@ -34,7 +33,7 @@ namespace base64 { - + QString encode( const QVariant & _data ) { QBuffer buf; diff --git a/src/core/fft_helpers.cpp b/src/core/fft_helpers.cpp index 71e84a8db..11f619c4a 100644 --- a/src/core/fft_helpers.cpp +++ b/src/core/fft_helpers.cpp @@ -2,7 +2,7 @@ * fft_helpers.cpp - some functions around FFT analysis * * Copyright (c) 2008-2012 Tobias Doerffel - * + * * This file is part of LMMS - http://lmms.io * * This program is free software; you can redistribute it and/or @@ -25,8 +25,8 @@ #include "fft_helpers.h" -#include "lmms_math.h" - +#include +#include "lmms_constants.h" /* returns biggest value from abs_spectrum[spec_size] array @@ -36,10 +36,10 @@ float maximum(float *abs_spectrum, unsigned int spec_size) { float maxi=0; unsigned int i; - + if ( abs_spectrum==NULL ) return -1; - + if (spec_size<=0) return -1; @@ -48,7 +48,7 @@ float maximum(float *abs_spectrum, unsigned int spec_size) if ( abs_spectrum[i]>maxi ) maxi=abs_spectrum[i]; } - + return maxi; } @@ -60,21 +60,21 @@ int hanming(float *timebuffer, int length, WINDOWS type) { int i; float alpha; - + if ( (timebuffer==NULL)||(length<=0) ) return -1; - + switch (type) { case HAMMING: alpha=0.54; break; - case HANNING: + case HANNING: default: alpha=0.5; break; } - + for ( i=0; i num_new - + returns 0 on success, else -1 */ int compressbands(float *absspec_buffer, float *compressedband, int num_old, int num_new, int bottom, int top) { @@ -114,13 +114,13 @@ int compressbands(float *absspec_buffer, float *compressedband, int num_old, int int i, usefromold; float j; float j_min, j_max; - + if ( (absspec_buffer==NULL)||(compressedband==NULL) ) return -1; - + if ( num_old #endif -#include #include #include -#include #include #include #include -#include -#include #include -#include -#include +#include #ifdef LMMS_BUILD_WIN32 #include @@ -71,16 +66,13 @@ #include "MemoryManager.h" #include "ConfigManager.h" #include "NotePlayHandle.h" -#include "embed.h" #include "Engine.h" #include "GuiApplication.h" -#include "LmmsStyle.h" #include "ImportFilter.h" #include "MainWindow.h" #include "ProjectRenderer.h" #include "DataFile.h" #include "Song.h" -#include "LmmsPalette.h" static inline QString baseName( const QString & _file ) { @@ -199,6 +191,7 @@ int main( int argc, char * * argv ) "-x, --oversampling specify oversampling\n" " possible values: 1, 2, 4, 8\n" " default: 2\n" + "-a, --float 32bit float bit depth\n" "-u, --upgrade [out] upgrade file and save as \n" " standard out is used if no output file is specifed\n" "-d, --dump dump XML of compressed file \n" @@ -304,6 +297,12 @@ int main( int argc, char * * argv ) } ++i; } + else if ( argc > i && + ( QString( argv[i] ) =="--float" || + QString( argv[i] ) == "-a" ) ) + { + os.depth = ProjectRenderer::Depth_32Bit; + } else if( argc > i && ( QString( argv[i] ) == "--interpolation" || QString( argv[i] ) == "-i" ) ) diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index fd86ffc84..0d19ec6aa 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -518,6 +518,10 @@ void FileBrowserTreeWidget::mouseMoveEvent( QMouseEvent * me ) new StringPairDrag( "importedproject", f->fullName(), embed::getIconPixmap( "midi_file" ), this ); break; + case FileItem::ProjectFile: + new StringPairDrag( "projectfile", f->fullName(), + embed::getIconPixmap( "project_file" ), this ); + break; default: break; diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 612a7409e..b8ddd6071 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -83,7 +83,6 @@ MainWindow::MainWindow() : vbox->setSpacing( 0 ); vbox->setMargin( 0 ); - QWidget * w = new QWidget( main_widget ); QHBoxLayout * hbox = new QHBoxLayout( w ); hbox->setSpacing( 0 ); @@ -94,24 +93,25 @@ MainWindow::MainWindow() : QSplitter * splitter = new QSplitter( Qt::Horizontal, w ); splitter->setChildrenCollapsible( false ); - QString wdir = ConfigManager::inst()->workingDir(); + ConfigManager* confMgr = ConfigManager::inst(); + sideBar->appendTab( new PluginBrowser( splitter ) ); sideBar->appendTab( new FileBrowser( - ConfigManager::inst()->userProjectsDir() + "*" + - ConfigManager::inst()->factoryProjectsDir(), + confMgr->userProjectsDir() + "*" + + confMgr->factoryProjectsDir(), "*.mmp *.mmpz *.xml *.mid *.flp", tr( "My Projects" ), embed::getIconPixmap( "project_file" ).transformed( QTransform().rotate( 90 ) ), splitter, false, true ) ); sideBar->appendTab( new FileBrowser( - ConfigManager::inst()->userSamplesDir() + "*" + - ConfigManager::inst()->factorySamplesDir(), + confMgr->userSamplesDir() + "*" + + confMgr->factorySamplesDir(), "*", tr( "My Samples" ), embed::getIconPixmap( "sample_file" ).transformed( QTransform().rotate( 90 ) ), splitter, false, true ) ); sideBar->appendTab( new FileBrowser( - ConfigManager::inst()->userPresetsDir() + "*" + - ConfigManager::inst()->factoryPresetsDir(), + confMgr->userPresetsDir() + "*" + + confMgr->factoryPresetsDir(), "*.xpf *.cs.xml *.xiz", tr( "My Presets" ), embed::getIconPixmap( "preset_file" ).transformed( QTransform().rotate( 90 ) ), @@ -121,33 +121,30 @@ MainWindow::MainWindow() : embed::getIconPixmap( "home" ).transformed( QTransform().rotate( 90 ) ), splitter, false, true ) ); + QStringList root_paths; + QString title = tr( "Root directory" ); + bool dirs_as_items = false; + #ifdef LMMS_BUILD_APPLE + title = tr( "Volumes" ); root_paths += "/Volumes"; -#else +#elif defined(LMMS_BUILD_WIN32) + title = tr( "My Computer" ); + dirs_as_items = true; +#endif + +#if ! defined(LMMS_BUILD_APPLE) QFileInfoList drives = QDir::drives(); foreach( const QFileInfo & drive, drives ) { root_paths += drive.absolutePath(); } #endif - sideBar->appendTab( new FileBrowser( root_paths.join( "*" ), "*", -#ifdef LMMS_BUILD_WIN32 - tr( "My Computer" ), -#elif defined(LMMS_BUILD_APPLE) - tr( "Volumes" ), -#else - tr( "Root Directory" ), -#endif + sideBar->appendTab( new FileBrowser( root_paths.join( "*" ), "*", title, embed::getIconPixmap( "computer" ).transformed( QTransform().rotate( 90 ) ), - splitter, -#ifdef LMMS_BUILD_WIN32 - true -#else - false -#endif - ) ); + splitter, dirs_as_items) ); m_workspace = new QMdiArea( splitter ); @@ -190,13 +187,13 @@ MainWindow::MainWindow() : vbox->addWidget( w ); setCentralWidget( main_widget ); - m_updateTimer.start( 1000 / 20, this ); // 20 fps + m_updateTimer.start( 1000 / 20, this ); // 20 fps if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() ) { // connect auto save connect(&m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(autoSave())); - m_autoSaveTimer.start(1000 * 60); // 1 minute + m_autoSaveTimer.start(1000 * 60); // 1 minute } connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), @@ -208,12 +205,10 @@ MainWindow::MainWindow() : MainWindow::~MainWindow() { - for( QList::iterator it = m_tools.begin(); - it != m_tools.end(); ++it ) + for( PluginView *view : m_tools ) { - Model * m = ( *it )->model(); - delete *it; - delete m; + delete view->model(); + delete view; } // TODO: Close tools // destroy engine which will do further cleanups etc. @@ -835,8 +830,13 @@ bool MainWindow::saveProjectAs() if( sfd.exec () == FileDialog::Accepted && !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" ) { + QString fname = sfd.selectedFiles()[0] ; + if( sfd.selectedNameFilter().contains( "(*.mpt)" ) && !sfd.selectedFiles()[0].endsWith( ".mpt" ) ) + { + fname += ".mpt"; + } Engine::getSong()->guiSaveProjectAs( - sfd.selectedFiles()[0] ); + fname ); return( true ); } return( false ); diff --git a/src/gui/PluginBrowser.cpp b/src/gui/PluginBrowser.cpp index 5c10dd368..96f33ae75 100644 --- a/src/gui/PluginBrowser.cpp +++ b/src/gui/PluginBrowser.cpp @@ -88,8 +88,6 @@ PluginBrowser::~PluginBrowser() - - PluginDescList::PluginDescList(QWidget *parent) : QWidget(parent) { @@ -98,7 +96,6 @@ PluginDescList::PluginDescList(QWidget *parent) : Plugin::getDescriptorsOfAvailPlugins( m_pluginDescriptors ); std::sort(m_pluginDescriptors.begin(), m_pluginDescriptors.end(), pluginBefore); - for( Plugin::DescriptorList::const_iterator it = m_pluginDescriptors.constBegin(); it != m_pluginDescriptors.constEnd(); ++it ) { @@ -117,8 +114,6 @@ PluginDescList::PluginDescList(QWidget *parent) : - - PluginDescWidget::PluginDescWidget( const Plugin::Descriptor & _pd, QWidget * _parent ) : QWidget( _parent ), @@ -181,7 +176,6 @@ void PluginDescWidget::paintEvent( QPaintEvent * ) m_targetHeight = qMax( 60, 25 + br.height() ); } } - } @@ -237,6 +231,7 @@ void PluginDescWidget::updateHeight() m_updateTimer.stop(); return; } + if( !m_updateTimer.isActive() ) { m_updateTimer.start( 15 ); diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index 953a9cd0b..870d7288d 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -39,6 +39,7 @@ #include "NStateButton.h" #include "GuiApplication.h" #include "TextFloat.h" +#include "SongEditor.h" #if QT_VERSION < 0x040800 @@ -280,7 +281,7 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) { return; } - if( event->button() == Qt::LeftButton ) + if( event->button() == Qt::LeftButton && !(event->modifiers() & Qt::ShiftModifier) ) { m_action = MovePositionMarker; if( event->x() - m_xOffset < s_posMarkerPixmap->width() ) @@ -292,6 +293,11 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) m_moveXOff = s_posMarkerPixmap->width() / 2; } } + else if( event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier) ) + { + m_action = SelectSongTCO; + m_initalXSelect = event->x(); + } else if( event->button() == Qt::RightButton || event->button() == Qt::MiddleButton ) { m_moveXOff = s_posMarkerPixmap->width() / 2; @@ -373,6 +379,9 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) update(); break; } + case SelectSongTCO: + emit regionSelectedFromPixels( m_initalXSelect , event->x() ); + break; default: break; @@ -386,6 +395,7 @@ void TimeLineWidget::mouseReleaseEvent( QMouseEvent* event ) { delete m_hint; m_hint = NULL; + if ( m_action == SelectSongTCO ) { emit selectionFinished(); } m_action = NoAction; } diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index a2d3ce12b..23250dc10 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -45,6 +45,7 @@ #include "Song.h" #include "StringPairDrag.h" #include "Track.h" +#include "GuiApplication.h" TrackContainerView::TrackContainerView( TrackContainer * _tc ) : @@ -307,12 +308,25 @@ void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) { StringPairDrag::processDragEnterEvent( _dee, QString( "presetfile,pluginpresetfile,samplefile,instrument," - "importedproject,soundfontfile,vstpluginfile," + "importedproject,soundfontfile,vstpluginfile,projectfile," "track_%1,track_%2" ). arg( Track::InstrumentTrack ). arg( Track::SampleTrack ) ); } +void TrackContainerView::selectRegionFromPixels(int xStart, int xEnd) +{ + m_rubberBand->setEnabled( true ); + m_rubberBand->show(); + m_rubberBand->setGeometry( min( xStart, xEnd ), 0, max( xStart, xEnd ) - min( xStart, xEnd ), std::numeric_limits::max() ); +} + +void TrackContainerView::stopRubberBand() +{ + m_rubberBand->hide(); + m_rubberBand->setEnabled( false ); +} + @@ -360,6 +374,16 @@ void TrackContainerView::dropEvent( QDropEvent * _de ) ImportFilter::import( value, m_tc ); _de->accept(); } + + else if( type == "projectfile") + { + if( gui->mainWindow()->mayChangeProject() ) + { + Engine::getSong()->loadProject( value ); + } + _de->accept(); + } + else if( type.left( 6 ) == "track_" ) { DataFile dataFile( value.toUtf8() ); diff --git a/src/gui/dialogs/VersionedSaveDialog.cpp b/src/gui/dialogs/VersionedSaveDialog.cpp index ae7f5305e..476046371 100644 --- a/src/gui/dialogs/VersionedSaveDialog.cpp +++ b/src/gui/dialogs/VersionedSaveDialog.cpp @@ -72,7 +72,7 @@ VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, bool VersionedSaveDialog::changeFileNameVersion(QString &fileName, bool increment ) { - static QRegExp regexp( "-\\d+(\\.\\w+)?$" ); + static QRegExp regexp( "[- ]\\d+(\\.\\w+)?$" ); int idx = regexp.indexIn( fileName ); // For file names without extension (no ".mmpz") diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index f839eb5a6..7c4b77dbf 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -64,6 +64,8 @@ #include "PianoRoll.h" #include "debug.h" #include "MeterModel.h" +#include "StringPairDrag.h" +#include "ProjectJournal.h" QPixmap * AutomationEditor::s_toolDraw = NULL; @@ -445,7 +447,6 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) { return; } - if( mouseEvent->y() > TOP_MARGIN ) { float level = getLevel( mouseEvent->y() ); @@ -491,6 +492,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) if( mouseEvent->button() == Qt::LeftButton && m_editMode == DRAW ) { + m_pattern->addJournalCheckPoint(); // Connect the dots if( mouseEvent->modifiers() & Qt::ShiftModifier ) { @@ -535,6 +537,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) m_editMode == DRAW ) || m_editMode == ERASE ) { + m_pattern->addJournalCheckPoint(); // erase single value if( it != time_map.end() ) { @@ -564,6 +567,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) else if( mouseEvent->button() == Qt::LeftButton && m_editMode == MOVE ) { + m_pattern->addJournalCheckPoint(); // move selection (including selected values) // save position where move-process began @@ -1658,6 +1662,7 @@ void AutomationEditor::setProgressionType(AutomationPattern::ProgressionTypes ty { if (validPattern()) { + m_pattern->addJournalCheckPoint(); QMutexLocker m(&m_patternMutex); m_pattern->setProgressionType(type); Engine::getSong()->setModified(); @@ -1797,6 +1802,7 @@ void AutomationEditor::cutSelectedValues() return; } + m_pattern->addJournalCheckPoint(); m_valuesToCopy.clear(); timeMap selected_values; @@ -1826,6 +1832,7 @@ void AutomationEditor::pasteValues() QMutexLocker m( &m_patternMutex ); if( validPattern() && !m_valuesToCopy.isEmpty() ) { + m_pattern->addJournalCheckPoint(); for( timeMap::iterator it = m_valuesToCopy.begin(); it != m_valuesToCopy.end(); ++it ) { @@ -1852,6 +1859,7 @@ void AutomationEditor::deleteSelectedValues() return; } + m_pattern->addJournalCheckPoint(); timeMap selected_values; getSelectedValues( selected_values ); @@ -2220,6 +2228,8 @@ AutomationEditorWindow::AutomationEditorWindow() : setFocusPolicy( Qt::StrongFocus ); setFocus(); setWindowIcon( embed::getIconPixmap( "automation" ) ); + setAcceptDrops( true ); + m_toolBar->setAcceptDrops( true ); } @@ -2282,6 +2292,30 @@ const AutomationPattern* AutomationEditorWindow::currentPattern() return m_editor->currentPattern(); } +void AutomationEditorWindow::dropEvent( QDropEvent *_de ) +{ + QString type = StringPairDrag::decodeKey( _de ); + QString val = StringPairDrag::decodeValue( _de ); + if( type == "automatable_model" ) + { + AutomatableModel * mod = dynamic_cast( + Engine::projectJournal()-> + journallingObject( val.toInt() ) ); + if( mod != NULL ) + { + m_editor->m_pattern->addObject( mod ); + setCurrentPattern( m_editor->m_pattern ); + } + } + + update(); +} + +void AutomationEditorWindow::dragEnterEvent( QDragEnterEvent *_dee ) +{ + StringPairDrag::processDragEnterEvent( _dee, "automatable_model" ); +} + void AutomationEditorWindow::open(AutomationPattern* pattern) { setCurrentPattern(pattern); diff --git a/src/gui/editors/BBEditor.cpp b/src/gui/editors/BBEditor.cpp index 667b88545..db14eecf6 100644 --- a/src/gui/editors/BBEditor.cpp +++ b/src/gui/editors/BBEditor.cpp @@ -22,13 +22,15 @@ * */ +#include "BBEditor.h" + #include #include #include #include #include -#include "BBEditor.h" +#include "ComboBox.h" #include "BBTrackContainer.h" #include "embed.h" #include "MainWindow.h" @@ -156,8 +158,6 @@ void BBEditor::stop() - - BBTrackContainerView::BBTrackContainerView(BBTrackContainer* tc) : TrackContainerView(tc), m_bbtc(tc) @@ -168,8 +168,6 @@ BBTrackContainerView::BBTrackContainerView(BBTrackContainer* tc) : - - void BBTrackContainerView::addSteps() { TrackContainer::TrackList tl = model()->tracks(); @@ -224,6 +222,18 @@ void BBTrackContainerView::removeBBView(int bb) +void BBTrackContainerView::saveSettings(QDomDocument& doc, QDomElement& element) +{ + MainWindow::saveWidgetState(parentWidget(), element); +} + +void BBTrackContainerView::loadSettings(const QDomElement& element) +{ + MainWindow::restoreWidgetState(parentWidget(), element); +} + + + void BBTrackContainerView::dropEvent(QDropEvent* de) { @@ -254,17 +264,3 @@ void BBTrackContainerView::updatePosition() //realignTracks(); emit positionChanged( m_currentPosition ); } - -void BBEditor::closeEvent( QCloseEvent * _ce ) - { - if( parentWidget() ) - { - parentWidget()->hide(); - } - else - { - hide(); - } - _ce->ignore(); - } - diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index d837292b7..92f7f0f1e 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -375,7 +375,8 @@ PianoRoll::PianoRoll() : this, SLOT( quantizeChanged() ) ); // Set up scale model - const auto& chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance(); + const InstrumentFunctionNoteStacking::ChordTable& chord_table = + InstrumentFunctionNoteStacking::ChordTable::getInstance(); m_scaleModel.addItem( tr("No scale") ); for( const InstrumentFunctionNoteStacking::Chord& chord : chord_table ) @@ -416,6 +417,10 @@ PianoRoll::PianoRoll() : connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int, int ) ), this, SLOT( update() ) ); + + //connection for selecion from timeline + connect( m_timeLine, SIGNAL( regionSelectedFromPixels( int, int ) ), + this, SLOT( selectRegionFromPixels( int, int ) ) ); } @@ -588,6 +593,44 @@ void PianoRoll::hidePattern( Pattern* pattern ) } } +void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) +{ + + xStart -= WHITE_KEY_WIDTH; + xEnd -= WHITE_KEY_WIDTH; + + // select an area of notes + int pos_ticks = xStart * MidiTime::ticksPerTact() / m_ppt + + m_currentPosition; + int key_num = 0; + m_selectStartTick = pos_ticks; + m_selectedTick = 0; + m_selectStartKey = key_num; + m_selectedKeys = 1; + // change size of selection + + // get tick in which the cursor is posated + pos_ticks = xEnd * MidiTime::ticksPerTact() / m_ppt + + m_currentPosition; + key_num = 120; + + m_selectedTick = pos_ticks - m_selectStartTick; + if( (int) m_selectStartTick + m_selectedTick < 0 ) + { + m_selectedTick = -static_cast( + m_selectStartTick ); + } + m_selectedKeys = key_num - m_selectStartKey; + if( key_num <= m_selectStartKey ) + { + --m_selectedKeys; + } + + computeSelectedNotes( false ); +} + + + @@ -906,7 +949,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } ke->accept(); @@ -938,7 +982,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } ke->accept(); @@ -979,7 +1024,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } @@ -1020,7 +1066,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } @@ -1077,7 +1124,11 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) } case Qt::Key_Control: - if ( isActiveWindow() ) + // Enter selection mode if: + // -> this window is active + // -> shift is not pressed + // ( is shortcut for sticky note resize) + if ( !( ke->modifiers() & Qt::ShiftModifier ) && isActiveWindow() ) { m_ctrlMode = m_editMode; m_editMode = ModeSelect; @@ -1222,7 +1273,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) return; } - // if holding control, go to selection mode + // if holding control, go to selection mode unless shift is also pressed if( me->modifiers() & Qt::ControlModifier && m_editMode != ModeSelect ) { m_ctrlMode = m_editMode; @@ -1948,12 +1999,10 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) pauseTestNotes(); } - dragNotes( - me->x(), - me->y(), + dragNotes( me->x(), me->y(), me->modifiers() & Qt::AltModifier, - me->modifiers() & Qt::ShiftModifier - ); + me->modifiers() & Qt::ShiftModifier, + me->modifiers() & Qt::ControlModifier ); if( replay_note && m_action == ActionMoveNote && ! ( ( me->modifiers() & Qt::ShiftModifier ) && ! m_startedWithShift ) ) { @@ -2365,7 +2414,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) -void PianoRoll::dragNotes( int x, int y, bool alt, bool shift ) +void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) { // dragging one or more notes around @@ -2411,13 +2460,19 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift ) // will be our iterator in the following loop NoteVector::ConstIterator it = notes.begin(); + + int sNotes = selectionCount(); while( it != notes.end() ) { Note *note = *it; const int pos = note->pos().getTicks(); - // when resizing a note and holding shift: shift the following - // notes to preserve the melody - if( m_action == ActionResizeNote && shift ) + + // When resizing notes: + // If shift is pressed we resize and rearrange only the selected notes + // If shift + ctrl then we also rearrange all posterior notes (sticky) + // If shift is pressed but only one note is selected, apply sticky + if( m_action == ActionResizeNote && shift && + ( note->selected() || ctrl || sNotes == 1 ) ) { int shifted_pos = note->oldPos().getTicks() + shift_offset; if( shifted_pos && pos == shift_ref_pos ) @@ -3377,11 +3432,11 @@ void PianoRoll::finishRecordNote(const Note & n ) { if( it->key() == n.key() ) { - Note n( n.length(), it->pos(), + Note n1( n.length(), it->pos(), it->key(), it->getVolume(), it->getPanning() ); - n.quantizeLength( quantization() ); - m_pattern->addNote( n ); + n1.quantizeLength( quantization() ); + m_pattern->addNote( n1 ); update(); m_recordingNotes.erase( it ); break; @@ -3814,7 +3869,8 @@ int PianoRoll::quantization() const void PianoRoll::updateSemiToneMarkerMenu() { - const auto& chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance(); + const InstrumentFunctionNoteStacking::ChordTable& chord_table = + InstrumentFunctionNoteStacking::ChordTable::getInstance(); const InstrumentFunctionNoteStacking::Chord& scale = chord_table.getScaleByName( m_scaleModel.currentText() ); const InstrumentFunctionNoteStacking::Chord& chord = diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index a513485f3..a9dab5d83 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -98,6 +98,10 @@ SongEditor::SongEditor( Song * _song ) : SLOT( updatePosition( const MidiTime & ) ) ); connect( m_timeLine, SIGNAL( positionChanged( const MidiTime & ) ), this, SLOT( updatePosition( const MidiTime & ) ) ); + connect( m_timeLine, SIGNAL( regionSelectedFromPixels( int, int ) ), + this, SLOT( selectRegionFromPixels( int, int ) ) ); + connect( m_timeLine, SIGNAL( selectionFinished() ), + this, SLOT( stopRubberBand() ) ); m_positionLine = new positionLine( this ); diff --git a/src/gui/embed.cpp b/src/gui/embed.cpp index 08af0c0a2..4e6ecaa13 100644 --- a/src/gui/embed.cpp +++ b/src/gui/embed.cpp @@ -45,73 +45,70 @@ namespace #include "embedded_resources.h" -QPixmap getIconPixmap( const char * _name, int _w, int _h ) +QPixmap getIconPixmap( const char * pixmapName, int width, int height ) { - if( _w == -1 || _h == -1 ) + if( width == -1 || height == -1 ) { - // Return cached pixmap - QPixmap cached = s_pixmapCache.value( _name ); + // Return cached pixmap + QPixmap cached = s_pixmapCache.value( pixmapName ); if( !cached.isNull() ) { return cached; } // Or try to load it - QList formats = - QImageReader::supportedImageFormats(); + QList formats = QImageReader::supportedImageFormats(); QList candidates; - QPixmap p; + QPixmap pixmap; QString name; int i; - for ( i = 0; i < formats.size() && p.isNull(); ++i ) + for ( i = 0; i < formats.size() && pixmap.isNull(); ++i ) { - candidates << QString( _name ) + "." + formats.at( i ).data(); + candidates << QString( pixmapName ) + "." + formats.at( i ).data(); } #ifdef PLUGIN_NAME - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); - p = QPixmap( ConfigManager::inst()->artworkDir() + "plugins/" + + pixmap = QPixmap( ConfigManager::inst()->artworkDir() + "plugins/" + STRINGIFY( PLUGIN_NAME ) + "_" + name ); } #endif - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); - p = QPixmap( ConfigManager::inst()->artworkDir() + name ); + pixmap = QPixmap( ConfigManager::inst()->artworkDir() + name ); } // nothing found, so look in default-artwork-dir - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); - p = QPixmap( ConfigManager::inst()->defaultArtworkDir() - + name ); + pixmap = QPixmap( ConfigManager::inst()->defaultArtworkDir() + name ); } - for ( i = 0; i < candidates.size() && p.isNull(); ++i ) { + for ( i = 0; i < candidates.size() && pixmap.isNull(); ++i ) { name = candidates.at( i ); const embed::descriptor & e = findEmbeddedData( name.toUtf8().constData() ); // found? - if( QString( e.name ) == name ) + if( name == e.name ) { - p.loadFromData( e.data, e.size ); + pixmap.loadFromData( e.data, e.size ); } } // Fallback - if(p.isNull()) + if( pixmap.isNull() ) { - p = QPixmap( 1, 1 ); + pixmap = QPixmap( 1, 1 ); } // Save to cache and return - s_pixmapCache.insert( _name, p ); - return p; - + s_pixmapCache.insert( pixmapName, pixmap ); + return pixmap; } - return getIconPixmap( _name ). - scaled( _w, _h, Qt::IgnoreAspectRatio, + return getIconPixmap( pixmapName ). + scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); } diff --git a/src/gui/widgets/FadeButton.cpp b/src/gui/widgets/FadeButton.cpp index 3495ae959..4fea14f97 100644 --- a/src/gui/widgets/FadeButton.cpp +++ b/src/gui/widgets/FadeButton.cpp @@ -55,6 +55,11 @@ FadeButton::~FadeButton() { } +void FadeButton::setActiveColor( const QColor & activated_color ) +{ + m_activatedColor = activated_color; +} + diff --git a/src/gui/widgets/SideBar.cpp b/src/gui/widgets/SideBar.cpp index 409fbf771..990bae7f6 100644 --- a/src/gui/widgets/SideBar.cpp +++ b/src/gui/widgets/SideBar.cpp @@ -107,53 +107,56 @@ SideBar::~SideBar() -void SideBar::appendTab( SideBarWidget * _sbw ) +void SideBar::appendTab( SideBarWidget *widget ) { - SideBarButton * btn = new SideBarButton( orientation(), this ); - btn->setText( _sbw->title() ); - btn->setIcon( _sbw->icon() ); - btn->setCheckable( true ); - m_widgets[btn] = _sbw; - m_btnGroup.addButton( btn ); - addWidget( btn ); + SideBarButton *button = new SideBarButton( orientation(), this ); + button->setText( widget->title() ); + button->setIcon( widget->icon() ); + button->setCheckable( true ); + m_widgets[button] = widget; + m_btnGroup.addButton( button ); + addWidget( button ); - _sbw->hide(); - _sbw->setMinimumWidth( 200 ); + widget->hide(); + widget->setMinimumWidth( 200 ); - ToolTip::add( btn, _sbw->title() ); + ToolTip::add( button, widget->title() ); } -void SideBar::toggleButton( QAbstractButton * _btn ) +void SideBar::toggleButton( QAbstractButton * button ) { - QToolButton * toolButton = NULL; - QWidget * activeWidget = NULL; - for( ButtonMap::Iterator it = m_widgets.begin(); - it != m_widgets.end(); ++it ) + QToolButton *toolButton = NULL; + QWidget *activeWidget = NULL; + + for( auto it = m_widgets.begin(); it != m_widgets.end(); ++it ) { - QToolButton * curBtn = it.key(); - if( curBtn != _btn ) + QToolButton *curBtn = it.key(); + QWidget *curWidget = it.value(); + + if( curBtn == button ) + { + toolButton = curBtn; + activeWidget = curWidget; + } + else { curBtn->setChecked( false ); curBtn->setToolButtonStyle( Qt::ToolButtonIconOnly ); } - else + + if( curWidget ) { - toolButton = it.key(); - activeWidget = it.value(); - } - if( it.value() ) - { - it.value()->hide(); + curWidget->hide(); } } if( toolButton && activeWidget ) { - activeWidget->setVisible( _btn->isChecked() ); - toolButton->setToolButtonStyle( _btn->isChecked() ? + activeWidget->setVisible( button->isChecked() ); + toolButton->setToolButtonStyle( button->isChecked() ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonIconOnly ); } } diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index cd598529e..7fcf2b0dc 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -36,12 +36,14 @@ #include #include #include +#include #include "FileDialog.h" #include "InstrumentTrack.h" #include "AudioPort.h" #include "AutomationPattern.h" #include "BBTrack.h" +#include "CaptionMenu.h" #include "ConfigManager.h" #include "ControllerConnection.h" #include "debug.h" @@ -926,6 +928,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV connect( m_activityIndicator, SIGNAL( released() ), this, SLOT( activityIndicatorReleased() ) ); _it->setIndicator( m_activityIndicator ); + connect( &_it->m_mutedModel, SIGNAL( dataChanged() ), this, SLOT( muteChanged() ) ); setModel( _it ); } @@ -962,6 +965,30 @@ InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow() + +/*! \brief Create and assign a new FX Channel for this track */ +void InstrumentTrackView::createFxLine() +{ + int channelIndex = gui->fxMixerView()->addNewChannel(); + + Engine::fxMixer()->effectChannel( channelIndex )->m_name = getTrack()->name(); + + assignFxLine(channelIndex); +} + + + + +/*! \brief Assign a specific FX Channel for this track */ +void InstrumentTrackView::assignFxLine(int channelIndex) +{ + model()->effectChannelModel()->setValue( channelIndex ); + + gui->fxMixerView()->setCurrentFxLine( channelIndex ); +} + + + // TODO: Add windows to free list on freeInstrumentTrackWindow. // But, don't NULL m_window or disconnect signals. This will allow windows // that are being show/hidden frequently to stay connected. @@ -1130,6 +1157,59 @@ void InstrumentTrackView::midiConfigChanged() +void InstrumentTrackView::muteChanged() +{ + if(model()->m_mutedModel.value() ) + { + m_activityIndicator->setActiveColor( QApplication::palette().color( QPalette::Active, + QPalette::Highlight ) ); + } else + { + m_activityIndicator->setActiveColor( QApplication::palette().color( QPalette::Active, + QPalette::BrightText ) ); + } +} + + + + +QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) +{ + int channelIndex = model()->effectChannelModel()->value(); + + FxChannel *fxChannel = Engine::fxMixer()->effectChannel( channelIndex ); + + // If title allows interpolation, pass channel index and name + if ( title.contains( "%2" ) ) + { + title = title.arg( channelIndex ).arg( fxChannel->m_name ); + } + + QMenu *fxMenu = new QMenu( title ); + + QSignalMapper * fxMenuSignalMapper = new QSignalMapper(fxMenu); + + fxMenu->addAction( newFxLabel, this, SLOT( createFxLine() ) ); + fxMenu->addSeparator(); + + for (int i = 0; i < Engine::fxMixer()->fxChannels().size(); ++i) + { + FxChannel * currentChannel = Engine::fxMixer()->fxChannels()[i]; + + if ( currentChannel != fxChannel ) + { + QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); + QAction * action = fxMenu->addAction( label, fxMenuSignalMapper, SLOT( map() ) ); + fxMenuSignalMapper->setMapping(action, currentChannel->m_channelIndex); + } + } + + connect(fxMenuSignalMapper, SIGNAL(mapped(int)), this, SLOT(assignFxLine(int))); + + return fxMenu; +} + + class fxLineLcdSpinBox : public LcdSpinBox @@ -1148,6 +1228,30 @@ class fxLineLcdSpinBox : public LcdSpinBox gui->fxMixerView()->setFocus();// set focus to fxMixer window //engine::getFxMixerView()->raise(); } + + virtual void contextMenuEvent( QContextMenuEvent* event ) + { + // for the case, the user clicked right while pressing left mouse- + // button, the context-menu appears while mouse-cursor is still hidden + // and it isn't shown again until user does something which causes + // an QApplication::restoreOverrideCursor()-call... + mouseReleaseEvent( NULL ); + + QPointer contextMenu = new CaptionMenu( model()->displayName(), this ); + + // This condition is here just as a safety check, fxLineLcdSpinBox is aways + // created inside a TabWidget inside an InstrumentTrackWindow + if ( InstrumentTrackWindow* window = dynamic_cast( (QWidget *)this->parent()->parent() ) ) + { + QMenu *fxMenu = window->instrumentTrackView()->createFxMenu( tr( "Assign to:" ), tr( "New FX Channel" ) ); + contextMenu->addMenu( fxMenu ); + + contextMenu->addSeparator(); + } + addDefaultActions( contextMenu ); + contextMenu->exec( QCursor::pos() ); + } + }; diff --git a/src/tracks/Pattern.cpp b/src/tracks/Pattern.cpp index 10ce2bca1..c348f50b8 100644 --- a/src/tracks/Pattern.cpp +++ b/src/tracks/Pattern.cpp @@ -761,12 +761,16 @@ void PatternView::constructContextMenu( QMenu * _cm ) _cm->addAction( embed::getIconPixmap( "edit_rename" ), tr( "Change name" ), this, SLOT( changeName() ) ); - _cm->addSeparator(); - _cm->addAction( embed::getIconPixmap( "step_btn_add" ), - tr( "Add steps" ), m_pat, SLOT( addSteps() ) ); - _cm->addAction( embed::getIconPixmap( "step_btn_remove" ), - tr( "Remove steps" ), m_pat, SLOT( removeSteps() ) ); + if ( m_pat->type() == Pattern::BeatPattern ) + { + _cm->addSeparator(); + + _cm->addAction( embed::getIconPixmap( "step_btn_add" ), + tr( "Add steps" ), m_pat, SLOT( addSteps() ) ); + _cm->addAction( embed::getIconPixmap( "step_btn_remove" ), + tr( "Remove steps" ), m_pat, SLOT( removeSteps() ) ); + } } @@ -834,6 +838,7 @@ void PatternView::mousePressEvent( QMouseEvent * _me ) } else // note at step found { + m_pat->addJournalCheckPoint(); if( n->length() < 0 ) { n->setLength( 0 ); // set note as enabled beat note