diff -Nru hydrogen-0.9.6~beta1/build.sh hydrogen-0.9.6~beta2/build.sh --- hydrogen-0.9.6~beta1/build.sh 2011-07-06 07:25:51.000000000 +0000 +++ hydrogen-0.9.6~beta2/build.sh 2012-05-25 12:19:45.000000000 +0000 @@ -8,16 +8,16 @@ -DWANT_JACK=1 \ -DWANT_ALSA=1 \ -DWANT_LIBARCHIVE=1 \ - -DWANT_RUBBERBAND=0 \ + -DWANT_RUBBERBAND=1 \ -DWANT_OSS=1 \ -DWANT_PORTAUDIO=1 \ -DWANT_PORTMIDI=1 \ - -DWANT_LASH=1 \ + -DWANT_LASH=0 \ -DWANT_LRDF=1 \ -DWANT_COREAUDIO=1 \ -DWANT_COREMIDI=1 " -MAKE_OPTS="-j 2" +MAKE_OPTS="-j 3" H2FLAGS="-V0xf" BUILD_DIR=./build diff -Nru hydrogen-0.9.6~beta1/ChangeLog hydrogen-0.9.6~beta2/ChangeLog --- hydrogen-0.9.6~beta1/ChangeLog 2011-12-15 22:04:40.000000000 +0000 +++ hydrogen-0.9.6~beta2/ChangeLog 2012-05-25 12:19:45.000000000 +0000 @@ -3,7 +3,12 @@ * new build system (cmake) * add undo for song/pattern editor * jack-session support - * some bug fixes + * jack-midi support + * several bug fixes + * tabbed interface + * several small changes to the GUI + * improve ExportSong add use of TimeLineBPM, + RubberbandBatch processor and different types of resample interpolation 2011-03-15 the hydrogen team diff -Nru hydrogen-0.9.6~beta1/CMakeLists.txt hydrogen-0.9.6~beta2/CMakeLists.txt --- hydrogen-0.9.6~beta1/CMakeLists.txt 2011-11-27 11:11:37.000000000 +0000 +++ hydrogen-0.9.6~beta2/CMakeLists.txt 2012-05-25 12:19:45.000000000 +0000 @@ -1,6 +1,7 @@ # # CMAKE SETUP # + CMAKE_MINIMUM_REQUIRED(VERSION 2.6) SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) # The CMake Policy mechanism is designed to help keep existing projects building as new versions of CMake introduce changes in behavior. @@ -115,7 +116,7 @@ ENDIF(APPLE) ENDIF(WIN32) -EXECUTE_PROCESS(COMMAND svnversion -n OUTPUT_VARIABLE REVISION ) +EXECUTE_PROCESS(COMMAND git log --pretty=format:'%h' -n 1 OUTPUT_VARIABLE REVISION ) # # HEADER LIBRARY FUNCTIONS @@ -287,7 +288,7 @@ ADD_SUBDIRECTORY(src/synth) ADD_SUBDIRECTORY(src/gui) -INSTALL(DIRECTORY data DESTINATION ${SYS_DATA_PATH}/.. PATTERN ".svn" EXCLUDE) +INSTALL(DIRECTORY data DESTINATION ${SYS_DATA_PATH}/.. PATTERN ".git" EXCLUDE) IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES ${CMAKE_SOURCE_DIR}/linux/hydrogen.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") ENDIF() Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/doc/img/GUI_Sections_0.9.5_v2.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/doc/img/GUI_Sections_0.9.5_v2.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/doc/img/InstrumentMapping.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/doc/img/InstrumentMapping.png differ diff -Nru hydrogen-0.9.6~beta1/data/doc/manual.docbook hydrogen-0.9.6~beta2/data/doc/manual.docbook --- hydrogen-0.9.6~beta1/data/doc/manual.docbook 2011-12-09 11:31:43.000000000 +0000 +++ hydrogen-0.9.6~beta2/data/doc/manual.docbook 2012-05-25 12:19:45.000000000 +0000 @@ -57,13 +57,13 @@ If you want to compile Hydrogen yourself (see ), you can download the latest source files directly from our - subversion server with: + git repository with: - $ svn co http://svn.assembla.com/svn/hydrogen/trunk + $ git clone git://github.com/hydrogen-music/hydrogen.git A certain release can be fetched with: - $ svn co http://svn.assembla.com/svn/hydrogen/tags/0.9.5 + $ git checkout tags/0.9.5 Compiling Hydrogen depends on the following libraries: @@ -127,8 +127,8 @@
Using scons (pre-0.9.6) - Decompress the tarball or go to the directory where the subversion copy - was checked out: + Decompress the tarball or go to the directory where the git repository + was cloned: $ cd hydrogen-* @@ -167,8 +167,8 @@
Using cmake (0.9.6 and up) - Compiling with cmake can be done easily by using the build.sh script. Go to the directory where the subversion copy - was checked out and run the build.sh script without any arguments to display the help : + Compiling with cmake can be done easily by using the build.sh script. Go to the directory where the git repository + was cloned and run the build.sh script without any arguments to display the help : $ ./build.sh @@ -454,7 +454,7 @@ - + @@ -1372,39 +1372,15 @@ The name of the instrument depends on the drumkit that is loaded. This list below refers to the GMkit that is loaded by default. + Try to follow the GM midi standard as accurately as possible. This will ensure that switching between + drumkits goes smoothly. You are of course free to place your instruments anywhere in your drumkit, and + sometimes it isn't even possible to follow the GM standard, but it makes life a lot easier if you do. Keep in mind that it is the position of the instrument (within the loaded drumkit) that is linked to a MIDI-note/keyboard-key and not the name of the instrument. - + @@ -2144,6 +2120,12 @@ Random Pitch + + Midi out Channel and Note + + + Auto Stop-Note + It's important that you understand
+ + + +
+ Midi out settings + + Hydrogen is capable of generating midi messages that you can use + to trigger any external midi device or application. To do this you simply need to + configure the Midi out channel and Note for every instrument. As you can see + this is a very flexible approach that enables you to trigger samples or sounds + from multiple devices and/or apps. Finally you need to make sure the proper + Midi routing/wiring is in place and you're set. + + + From now on every time a note is played for that instrument (in the Hydrogen sequencer) + a midi message will be sent to your external app/device and trigger a sound. + This way you can use Hydrogen as a pure sequencer for other apps, or combine the + internal Hydrogen sampler with multiple external apps/devices. + +
+ +
+ Auto Stop-Note + + If this box is checked Hydrogen will immediately stop any playing sample that + belongs to this instrument whenever the instrument is re-triggered. + This option is particularly useful when you are using long samples like a + crash or some existing audio that you have sampled (like a looped voice in a + dance/electro song) For the crash you will need to use the Auto Stop-Note when + you are sequencing multiple notes in fast succession and want to make it sound realistic. If you do + not check this option the cymbal will start to sound like multiple cymbals + instead of only one (since the sample of each individual hit will be played completely). + For the voice sample this option is useful if you are trying to get that 'stuttering' effect. + + + +
+ +
@@ -2466,7 +2487,7 @@ If rubberband is installed correctly you will have access to the rubberband settings, and an extra button named 'RUB' will be available in the Main Toolbar, - right of the BPM LCD display : + right of the BPM LCD display: @@ -2479,7 +2500,7 @@ Back to the rubberband settings : - Sample length to beat : when set to 'off' rubberband functionality is disabled. + Sample length to beat : when set to 'off', rubberband functionality is disabled. Normally this parameter should be set to the length of the part of the sample between the Start and End marker, expressed in number of beats. @@ -2491,7 +2512,7 @@ - Note : If you want Hydrogen to recalculate the sample length on the fly (using rubberband) + Note: If you want Hydrogen to recalculate the sample length on the fly (using rubberband) you must enable the 'RUB' button (see figure above). @@ -2503,10 +2524,10 @@ of the tweaks you have made by pressing the Apply Changes button. You can also change the the Volume and Panorama (Pan) of your sample here. This is done by creating 'envelopes' like the - ones you find in numerous DAW's for (parameter) automation. To edit an + ones you find in numerous DAW's for automation. To edit an envelope you first need to select 'Volume' or 'Panorama'in the upper right - corner of section 3. The Volume envelope is blue, the pan envelope is yellow. - Left clicking in the bottom window will ad a node to an envelope, and also + corner of section 3. The Volume envelope is blue, and the pan envelope is yellow. + Left clicking in the bottom window will ad a node to an envelope and also allows you to drag an existing node. Right-clicking a node will delete it. Don't forget to Apply Changes before you play your tweaked sample. @@ -2517,12 +2538,12 @@ Tips on Editing Instruments With all of the different parameters available to tweak, it can be - difficult to set up something that sounds nice when you're done. Here's + difficult to set up something that sounds nice when you're done. Here are a few tips on setting up an instrument: - Turn down the gain. Every time - you have a gain knob (i.e. an amplifier), this is called a - gain stage. With every gain stage you have, it's + Turn down the gain. Every gain + knob (i.e. an amplifier), this is a gain stage. + With every gain stage you have, it's easy to overdrive your signal — which means the signal gets distorted by clipping. In addition, if you have two samples that, by themselves, peg your meters — what do you think happens when you @@ -2551,7 +2572,7 @@ also be on this line. However, if your signal is a little above or a little below this line, you will hear a click at the beginning and the end of your sample whenever it is played. If your sample editor doesn't - provide any tools to fix a DC Offset problem, you can eliminate the + provide any tools to fix a DC offset problem, you can eliminate the noise by putting a slight fade-in/out at the ends of your sample. The ADSR will not be longer than your @@ -2563,8 +2584,8 @@ rate. If you have a really nice setup with all your parameters painstakenly tweaked... things will change if you change the sample rate of your audio card. Many of - Hydrogens internal settings and parameters are done based on how many - samples go by, and not on how many seconds go by. The sort of things + Hydrogen's internal settings and parameters are based on how many + samples go by, not on how many seconds go by. The sorts of things that change are: anything time-base (like attack and release) and anything frequency based (like the cutoff frequency). @@ -2577,9 +2598,9 @@ Midi In this section you can find more info about defining MIDI actions - and how these can be useful for you. Before you can work with midi actions + and how they can be useful for you. Before you can work with midi actions you should have your Midi devices, drivers and connections configured - correctly (see ) + correctly (see ). Lets take a look at the available options : @@ -2597,22 +2618,22 @@ An Event is an incoming Midi message, coming from a MIDI controller or an external sequencer. - If you take a look at the Events list you will see that there are 3 types of Events + If you look at the Events list you will see that there are 3 types of Events available (as described in the Midi standard): - NOTE : input coming from a regular black/white key of a keyboard or a drumpad + NOTE: input coming from a regular black/white key of a keyboard or a drumpad - CC : controller commands coming from faders or rotary controllers + CC: controller commands coming from faders or rotary controllers - MMC_x : + MMC_x: machine control events coming from play/stop... buttons on a controller @@ -2620,7 +2641,7 @@ - The Param. (parameter) value right of the Event is the identifier of the note/button/controller + The Param. (parameter) value to the right of the Event is the identifier of the note/button/controller that is linked to this Action. This parameter can be entered manually, or automatically by using the Midi learn function (see ). @@ -2630,7 +2651,7 @@ a key or turn/move a controller. If you Shift-click on a gui element that does not support Midi automation a popup will - inform you about this. + inform you. @@ -2640,7 +2661,7 @@
Midi Actions - Next is a list of the available Actions : an Action describes what Hydrogen should do + Next is a list of the available Actions: an Action describes what Hydrogen should do when a specific Midi Event is detected. ** Some of the Midi Actions require that the Action Parameter is configured. The @@ -2657,7 +2678,7 @@ PLAY/STOP_TOGGLE : toggles between PLAY and STOP. Execute this action will start playback, execute it again and playback will stop + the playhead will return - to the start op the song + to the start of the song @@ -2666,11 +2687,11 @@ - STOP : stop playback and return to the start of the song + STOP : stops playback and returns to the start of the song - PAUSE : pause the song + PAUSE : pauses the song @@ -2702,7 +2723,7 @@ - BPM_CC_RELATIVE : change the tempo relative to the current tempo, using a controller + BPM_CC_RELATIVE : changes the tempo relative to the current tempo, using a controller @@ -2726,12 +2747,12 @@ - EFFECTx_LEVEL_RELATIVE : changes the volume level of effect 'x' - The value you enter in the Action Parameter determines the channel strip this action applies to ** + EFFECTx_LEVEL_RELATIVE : changes the volume level of effect 'x'; + the value you enter in the Action Parameter determines the channel strip this action applies to ** - SELECT_NEXT_PATTERN : will select the pattern that is defined in the Action Parameter ** + SELECT_NEXT_PATTERN : selects the pattern that is defined in the Action Parameter ** @@ -2739,22 +2760,20 @@ - PAN_RELATIVE : will change the panorama setting, relative to the current value - The value you enter in the Action Parameter determines the channel strip this action applies to ** + PAN_RELATIVE : changes the panorama setting, relative to the current value; + the value you enter in the Action Parameter determines the channel strip this action applies to ** - PAN_ABSOLUTE : will change the panorama setting to the absolute value that the linked controller sends to Hydrogen + PAN_ABSOLUTE : changes the panorama setting to the absolute value that the linked controller sends to Hydrogen - BEATCOUNTER : allows you to set - the tempo (see + BEATCOUNTER : sets the tempo (see - TAP_TEMPO : allows you to set - the tempo (see + TAP_TEMPO : sets the tempo (see @@ -2782,33 +2801,35 @@
"Song" mode and "Pattern" mode - This is just a quick-and-dirty walkthrough to Hydrogen. Refer to the + This section is a quick-and-dirty walkthrough to Hydrogen. Refer to the tutorial for a more detailed overview. Hydrogen has 2 main modes: "Pattern" mode and "Song" mode (refer to - for the buttons to activate). When + for the buttons that activate each mode). When "Pattern" mode is activated the current pattern is continuously repeated. - This mode is very well suited to tweak your pattern untill it's just right, since the + This mode is very well suited to tweak your pattern until it's just right, since the pattern you are working on is constantly repeated. This way you can immediately hear the changes you have made. In "Song" mode the whole song is played. - This is useful when putting together the patterns, to create the structure of the song. + This is useful when putting together the patterns to create the structure of the song.
A new pattern - We'll start from an empty song with an empty pattern, as created by - default: "pattern" mode should be selected now. It is also possible to - change name of the pattern. Now let's click on the Play - button and while the pattern is playing let's add notes in the grid of the - Song Editor () simply - left_mouse_clicking on it: adjust grid resolution and BPM speed if - needed. Remember some constraints of the grid: if you are working with a - resolution of 16 you can't go back to 8 and remove a 16th note; same thing - happens if you are working with a resolution of 8 and you try to insert a - note in the middle of two bars (looking for a 16 bars precision): they - will be placed on the previous or on the following 8th bar (unless you - choose off from the Grid Resolution LCD, in this case + + + + We'll start from the empty song with an empty pattern created when + Hydrogen starts up: "pattern" mode should be selected by default. Now + let's click on the Playbutton, and while the pattern is playing + let's add notes by left_mouse_clicking in the grid of the Song Editor + (). Adjust the grid resolution and BPM + speed if needed. Remember some constraints of the grid: if you are + working with a resolution of 16 you can't go back to 8 and remove a + 16th note; same thing happens if you are working with a resolution of + 8 and you try to insert a note in the middle of two bars (looking for + a 16 bars precision): they will be placed on the previous or on the + following 8th bar (unless you choose off from the Grid Resolution LCD in which case you're free to place notes wherever you prefer). Be sure to select the correct pattern in the Song Editor before adding notes in the Pattern Editor! @@ -2827,9 +2848,9 @@ A new sequence Once patterns are created (), we - can copy/paste/delete them simply dragging with the mouse (activate the - select mode for the Song Editor and keep pressed left mouse button to - select those you want to move or copy). + can copy/paste/delete them using the Select Mode (see ). + +
Inserting Notes in a Pattern @@ -2849,9 +2870,10 @@ or playing patterns. The Mixer frame () is made of 32 - independent tracks, each of these is binded to an instrument, plus a - "Master Output" line to adjust general output volume and a "FX" button to - set effects. Every line features 3 buttons ( + independent tracks, each of these is bound to an instrument, plus a + "Master Output" control and a "FX" button to show and hide the + effects panel. + Every line features 3 buttons ( @@ -2887,8 +2909,7 @@ - will play the selected instrument, cutting the others. The "Mute" - button + will play the selected instrument, cutting the others. The "Mute" button @@ -2897,11 +2918,11 @@ , simply mute that instrument. The maximum peak - indicates the maximum volume reached from the instrument; the peak must + indicates the maximum volume reached from the instrument. The peak must be in a range of 0.0 and 1.0 (in you can - see a few volumes too loud), otherwise it will get distorted producing a - weird sound (especially with OSS audio driver), in this case it's better - to set volume down; keep an eye on each vu-meter. + see a few volumes too loud). Peaks outside that range will get distorted + (especially with OSS audio driver). Keep an eye on each vu-meter and + if distortion appears, turn the volume down for that instrument.
@@ -3040,12 +3061,12 @@ Glossary This is a glossary of general terms encountered when using Hydrogen, - synthesizers, drums, or samplers. The definitions in the text are - simplified, but the definitions here are more general and have more - explanation. For example, the text of the manual would have you believe - that an ADSR is the only kind of envelope generator, and could only ever - control the volume. While it's simple for new users, it's not quite - right. + synthesizers, drums, or samplers. The definitions here provide more + detail and explanation than the simplified ones in the text. For + example, the text of the manual would have you believe that an ADSR is + the only kind of envelope generator and could only ever control the + volume. While the simplified definitions help new users start using + Hydrogen quickly, they can lack the nuances presented here. @@ -3164,6 +3185,20 @@ + + DC-offsety + + DC offset, or DC coefficient is the mean value of the wavefor.m + DC offset is usually undesirable. For example, in audio processing, a + sound that has DC offset will not be at its loudest possible volume when + normalized (because the offset consumes headroom), and this problem can + possibly extend to the mix as a whole, since a sound with DC offset and a sound + without DC offset will have DC offset when mixed. It may also cause other artifacts + depending on what is being done with the signal. + + + + diff -Nru hydrogen-0.9.6~beta1/data/doc/manual_en.html hydrogen-0.9.6~beta2/data/doc/manual_en.html --- hydrogen-0.9.6~beta1/data/doc/manual_en.html 2011-12-09 11:31:43.000000000 +0000 +++ hydrogen-0.9.6~beta2/data/doc/manual_en.html 2012-05-25 12:19:45.000000000 +0000 @@ -131,7 +131,7 @@

Below you can see the main UI split up in 5 parts : the Main Menu, Main Toolbar, Song Editor, Pattern Editor and the Instrument and Sound Library Editor. - These sections will be explained in detail further down in this manual.

Figure 2.1. The Main UI in Single Pane mode

The Main UI in Single Pane mode

Figure 2.2. The Main UI in Tabbed mode

The Main UI in Tabbed mode

Main menu

Projects: this menu offers file + These sections will be explained in detail further down in this manual.

Figure 2.1. The Main UI in Single Pane mode

The Main UI in Single Pane mode

Figure 2.2. The Main UI in Tabbed mode

The Main UI in Tabbed mode

Main menu

Projects: this menu offers file related functions.

  • New - Create a new song

  • Show Info - Set general properties of the song such as name, author, license and generic notes

  • Open - Open a song

  • Open Demo - Open a demo song (demo songs are stored in @@ -433,7 +433,9 @@ mapping : in the table below you can find the link between the instrument position, the MIDI note and the qwerty keyboard keys.

    Important Notes :

    The name of the instrument depends on the drumkit that is loaded. This list below refers to the GMkit that is loaded by default. -

    +

    Try to follow the GM midi standard as accurately as possible. This will ensure that switching between + drumkits goes smoothly. You are of course free to place your instruments anywhere in your drumkit, and + sometimes it isn't even possible to follow the GM standard, but it makes life a lot easier if you do.

    Keep in mind that it is the position of the instrument (within the loaded drumkit) that is linked to a MIDI-note/keyboard-key and not the name of the instrument.

    Here's a quick reference of the above bindings for your @@ -739,7 +741,7 @@ member of (see Mute Group).

  • Filter Parameters: Bypass, Cutoff, Resonance.

  • Random - Pitch

It's important that you understand the section called “Concepts” in order to continue + Pitch

  • Midi out Channel and Note

  • Auto Stop-Note

  • It's important that you understand the section called “Concepts” in order to continue on.

    Envelope Parameters

    When the instrument is triggered, its volume is run through an ADSR Envelope. The parameters operate as follows:

    • Attack — the amount of time that the volume of the sample goes @@ -799,7 +801,25 @@ of the sample every time it is triggered. The value is set between 0 and 1.0. The pitch change is fairly small: ±2 half-steps × value. Using this sparingly can help your sequences to sound - more like a real drummer.

    Creating an Instrument and Layers

    For each instrument in a drum kit, you can load several samples + more like a real drummer.

    Midi out settings

    Hydrogen is capable of generating midi messages that you can use + to trigger any external midi device or application. To do this you simply need to + configure the Midi out channel and Note for every instrument. As you can see + this is a very flexible approach that enables you to trigger samples or sounds + from multiple devices and/or apps. Finally you need to make sure the proper + Midi routing/wiring is in place and you're set. +

    From now on every time a note is played for that instrument (in the Hydrogen sequencer) + a midi message will be sent to your external app/device and trigger a sound. + This way you can use Hydrogen as a pure sequencer for other apps, or combine the + internal Hydrogen sampler with multiple external apps/devices.

    Auto Stop-Note

    If this box is checked Hydrogen will immediately stop any playing sample that + belongs to this instrument whenever the instrument is re-triggered.

    This option is particularly useful when you are using long samples like a + crash or some existing audio that you have sampled (like a looped voice in a + dance/electro song) For the crash you will need to use the Auto Stop-Note when + you are sequencing multiple notes in fast succession and want to make it sound realistic. If you do + not check this option the cymbal will start to sound like multiple cymbals + instead of only one (since the sample of each individual hit will be played completely). + For the voice sample this option is useful if you are trying to get that 'stuttering' effect. + +

    Creating an Instrument and Layers

    For each instrument in a drum kit, you can load several samples and set different synthesizer parameters. This section will step you through how to create a new instrument and load the samples.

    To begin creating an instrument, select InstrumentsAdd instrument. This will give you a blank @@ -893,31 +913,31 @@ . After installing rubberband you should check if the path to the rubberband cli is configured correctly (see the section called “The General tab”).

    If rubberband is installed correctly you will have access to the rubberband settings, and an extra button named 'RUB' will be available in the Main Toolbar, - right of the BPM LCD display : + right of the BPM LCD display:

    Back to the rubberband settings : -

    • Sample length to beat : when set to 'off' rubberband functionality is disabled. +

      • Sample length to beat : when set to 'off', rubberband functionality is disabled. Normally this parameter should be set to the length of the part of the sample between the Start and End marker, expressed in number of beats.

      • Pitch : this setting allows you to change the pitch of the sample, expressed in semitones,cent.

      • Crispness : this setting does not affect tempo or pitch, but changes the way the sample sounds.

      -

      Note : If you want Hydrogen to recalculate the sample length on the fly (using rubberband) +

      Note: If you want Hydrogen to recalculate the sample length on the fly (using rubberband) you must enable the 'RUB' button (see figure above).

    Sample Editor volume/pan

    In the bottom section of the Sample Editor you can see the end result of the tweaks you have made by pressing the Apply Changes button. You can also change the the Volume and Panorama (Pan) of your sample here. This is done by creating 'envelopes' like the - ones you find in numerous DAW's for (parameter) automation. To edit an + ones you find in numerous DAW's for automation. To edit an envelope you first need to select 'Volume' or 'Panorama'in the upper right - corner of section 3. The Volume envelope is blue, the pan envelope is yellow. - Left clicking in the bottom window will ad a node to an envelope, and also + corner of section 3. The Volume envelope is blue, and the pan envelope is yellow. + Left clicking in the bottom window will ad a node to an envelope and also allows you to drag an existing node. Right-clicking a node will delete it. Don't forget to Apply Changes before you play your tweaked sample.

    Tips on Editing Instruments

    With all of the different parameters available to tweak, it can be - difficult to set up something that sounds nice when you're done. Here's - a few tips on setting up an instrument:

    Turn down the gain. Every time - you have a gain knob (i.e. an amplifier), this is called a - gain stage. With every gain stage you have, it's + difficult to set up something that sounds nice when you're done. Here are + a few tips on setting up an instrument:

    Turn down the gain. Every gain + knob (i.e. an amplifier), this is a gain stage. + With every gain stage you have, it's easy to overdrive your signal — which means the signal gets distorted by clipping. In addition, if you have two samples that, by themselves, peg your meters — what do you think happens when you @@ -938,7 +958,7 @@ also be on this line. However, if your signal is a little above or a little below this line, you will hear a click at the beginning and the end of your sample whenever it is played. If your sample editor doesn't - provide any tools to fix a DC Offset problem, you can eliminate the + provide any tools to fix a DC offset problem, you can eliminate the noise by putting a slight fade-in/out at the ends of your sample.

    The ADSR will not be longer than your sample. If you have a short sample, it doesn't matter how long you set the attack and delay — the sample will stop playing @@ -946,34 +966,34 @@ rate. If you have a really nice setup with all your parameters painstakenly tweaked... things will change if you change the sample rate of your audio card. Many of - Hydrogens internal settings and parameters are done based on how many - samples go by, and not on how many seconds go by. The sort of things + Hydrogen's internal settings and parameters are based on how many + samples go by, not on how many seconds go by. The sorts of things that change are: anything time-base (like attack and release) and anything frequency based (like the cutoff frequency).

    Midi

    In this section you can find more info about defining MIDI actions - and how these can be useful for you. Before you can work with midi actions + and how they can be useful for you. Before you can work with midi actions you should have your Midi devices, drivers and connections configured - correctly (see the section called “The Midi System tab”) + correctly (see the section called “The Midi System tab”).

    Lets take a look at the available options :

    Midi Events

    An Event is an incoming Midi message, coming from a MIDI controller or - an external sequencer.

    If you take a look at the Events list you will see that there are 3 types of Events + an external sequencer.

    If you look at the Events list you will see that there are 3 types of Events available (as described in the Midi standard):

    • - NOTE : input coming from a regular black/white key of a keyboard or a drumpad + NOTE: input coming from a regular black/white key of a keyboard or a drumpad

    • - CC : controller commands coming from faders or rotary controllers + CC: controller commands coming from faders or rotary controllers

    • - MMC_x : + MMC_x: machine control events coming from play/stop... buttons on a controller

    - The Param. (parameter) value right of the Event is the identifier of the note/button/controller + The Param. (parameter) value to the right of the Event is the identifier of the note/button/controller that is linked to this Action. This parameter can be entered manually, or automatically by using the Midi learn function (see the section called “The Midi System tab”).

    Note

    You can also activate the Midi learn function by Shift-clicking most of the gui elements. A 'Waiting for Midi input...' popup informs you that Hydrogen is now waiting for you to press a key or turn/move a controller.

    If you Shift-click on a gui element that does not support Midi automation a popup will - inform you about this. -

    Midi Actions

    Next is a list of the available Actions : an Action describes what Hydrogen should do + inform you. +

    Midi Actions

    Next is a list of the available Actions: an Action describes what Hydrogen should do when a specific Midi Event is detected.

    Note

    ** Some of the Midi Actions require that the Action Parameter is configured. The Parameter usually references a specific channel, instrument, FXsend... Keep in mind that the Parameter value is zero-based. So if you want to reference channel 1 you @@ -982,14 +1002,14 @@

  • PLAY/STOP_TOGGLE : toggles between PLAY and STOP. Execute this action will start playback, execute it again and playback will stop + the playhead will return - to the start op the song + to the start of the song

  • PLAY/PAUSE_TOGGLE : toggles between PLAY and PAUSE. (the playhead will not return to the start of the song, but will stay at its current position)

  • - STOP : stop playback and return to the start of the song + STOP : stops playback and returns to the start of the song

  • - PAUSE : pause the song + PAUSE : pauses the song

  • MUTE : mutes the the Master output (sequencer keeps running)

  • @@ -1005,7 +1025,7 @@

  • BPM_DECR : decrements the tempo of the song

  • - BPM_CC_RELATIVE : change the tempo relative to the current tempo, using a controller + BPM_CC_RELATIVE : changes the tempo relative to the current tempo, using a controller

  • MASTER_VOLUME_RELATIVE : changes the Master output volume, relative to the current setting (e.g. if you are using rotary encoders) @@ -1019,58 +1039,55 @@ STRIP_VOLUME_ABSOLUTE : see MASTER_VOLUME_ABSOLUTE, but applies to the channel strip defined in the Action Parameter **

  • - EFFECTx_LEVEL_RELATIVE : changes the volume level of effect 'x' - The value you enter in the Action Parameter determines the channel strip this action applies to ** + EFFECTx_LEVEL_RELATIVE : changes the volume level of effect 'x'; + the value you enter in the Action Parameter determines the channel strip this action applies to **

  • - SELECT_NEXT_PATTERN : will select the pattern that is defined in the Action Parameter ** + SELECT_NEXT_PATTERN : selects the pattern that is defined in the Action Parameter **

  • SELECT_AND_PLAY_NEXT_PATTERN : combines the SELECT_NEXT_PATTERN with PLAY

  • - PAN_RELATIVE : will change the panorama setting, relative to the current value - The value you enter in the Action Parameter determines the channel strip this action applies to ** + PAN_RELATIVE : changes the panorama setting, relative to the current value; + the value you enter in the Action Parameter determines the channel strip this action applies to **

  • - PAN_ABSOLUTE : will change the panorama setting to the absolute value that the linked controller sends to Hydrogen + PAN_ABSOLUTE : changes the panorama setting to the absolute value that the linked controller sends to Hydrogen

  • - BEATCOUNTER : allows you to set - the tempo (see the section called “Tap Tempo and BeatCounter” + BEATCOUNTER : sets the tempo (see the section called “Tap Tempo and BeatCounter”

  • - TAP_TEMPO : allows you to set - the tempo (see the section called “Tap Tempo and BeatCounter” + TAP_TEMPO : sets the tempo (see the section called “Tap Tempo and BeatCounter”

  • SELECT_INSTRUMENT : selects one of the instruments in the drumkit



  • [1] The attack, decay, and release parameters are all set by the number of audio samples. This means that the time changes depending on the sample rate of your sound card. The max time for each of them is 100,000 audio samples - (typ. 2.27 sec at 44.1 kHz).

    Chapter 3. A new song

    "Song" mode and "Pattern" mode

    This is just a quick-and-dirty walkthrough to Hydrogen. Refer to the + (typ. 2.27 sec at 44.1 kHz).

    Chapter 3. A new song

    "Song" mode and "Pattern" mode

    This section is a quick-and-dirty walkthrough to Hydrogen. Refer to the tutorial for a more detailed overview.

    Hydrogen has 2 main modes: "Pattern" mode and "Song" mode (refer to - the section called “The main toolbar” for the buttons to activate). When + the section called “The main toolbar” for the buttons that activate each mode). When "Pattern" mode is activated the current pattern is continuously repeated. - This mode is very well suited to tweak your pattern untill it's just right, since the + This mode is very well suited to tweak your pattern until it's just right, since the pattern you are working on is constantly repeated. This way you can immediately hear the changes you have made. In "Song" mode the whole song is played. - This is useful when putting together the patterns, to create the structure of the song.

    A new pattern

    We'll start from an empty song with an empty pattern, as created by - default: "pattern" mode should be selected now. It is also possible to - change name of the pattern. Now let's click on the Play - button and while the pattern is playing let's add notes in the grid of the - Song Editor (Figure 3.1, “The Pattern Editor”) simply - left_mouse_clicking on it: adjust grid resolution and BPM speed if - needed. Remember some constraints of the grid: if you are working with a - resolution of 16 you can't go back to 8 and remove a 16th note; same thing - happens if you are working with a resolution of 8 and you try to insert a - note in the middle of two bars (looking for a 16 bars precision): they - will be placed on the previous or on the following 8th bar (unless you - choose off from the Grid Resolution LCD, in this case + This is useful when putting together the patterns to create the structure of the song.

    A new pattern

    We'll start from the empty song with an empty pattern created when + Hydrogen starts up: "pattern" mode should be selected by default. Now + let's click on the Playbutton, and while the pattern is playing + let's add notes by left_mouse_clicking in the grid of the Song Editor + (Figure 3.1, “The Pattern Editor”). Adjust the grid resolution and BPM + speed if needed. Remember some constraints of the grid: if you are + working with a resolution of 16 you can't go back to 8 and remove a + 16th note; same thing happens if you are working with a resolution of + 8 and you try to insert a note in the middle of two bars (looking for + a 16 bars precision): they will be placed on the previous or on the + following 8th bar (unless you choose off from the Grid Resolution LCD in which case you're free to place notes wherever you prefer). Be sure to select the correct pattern in the Song Editor before adding notes in the Pattern Editor!

    Figure 3.1. The Pattern Editor

    The Pattern Editor

    A new sequence

    Once patterns are created (Figure 3.2, “Inserting Notes in a Pattern”), we - can copy/paste/delete them simply dragging with the mouse (activate the - select mode for the Song Editor and keep pressed left mouse button to - select those you want to move or copy).

    Figure 3.2. Inserting Notes in a Pattern

    Inserting Notes in a Pattern

    Adjust from the mixer

    Of course we can always use the mixer window, either when creating + can copy/paste/delete them using the Select Mode (see the section called “Main controls”). +

    Figure 3.2. Inserting Notes in a Pattern

    Inserting Notes in a Pattern

    Adjust from the mixer

    Of course we can always use the mixer window, either when creating or playing patterns.

    The Mixer frame (Figure 3.3, “The Mixer”) is made of 32 - independent tracks, each of these is binded to an instrument, plus a - "Master Output" line to adjust general output volume and a "FX" button to - set effects. Every line features 3 buttons ( + independent tracks, each of these is bound to an instrument, plus a + "Master Output" control and a "FX" button to show and hide the + effects panel. + Every line features 3 buttons ( @@ -1086,17 +1103,16 @@ - will play the selected instrument, cutting the others. The "Mute" - button + will play the selected instrument, cutting the others. The "Mute" button , simply mute that instrument. The maximum peak - indicates the maximum volume reached from the instrument; the peak must + indicates the maximum volume reached from the instrument. The peak must be in a range of 0.0 and 1.0 (in Figure 3.3, “The Mixer” you can - see a few volumes too loud), otherwise it will get distorted producing a - weird sound (especially with OSS audio driver), in this case it's better - to set volume down; keep an eye on each vu-meter. + see a few volumes too loud). Peaks outside that range will get distorted + (especially with OSS audio driver). Keep an eye on each vu-meter and + if distortion appears, turn the volume down for that instrument.

    Figure 3.3. The Mixer

    The Mixer

    Chapter 4. Shortcut lists

    • [CTRL + N] = New Project

    • @@ -1144,12 +1160,12 @@ [F12] = Panic button (stops the song and mutes all playing sounds)

    Glossary

    This is a glossary of general terms encountered when using Hydrogen, - synthesizers, drums, or samplers. The definitions in the text are - simplified, but the definitions here are more general and have more - explanation. For example, the text of the manual would have you believe - that an ADSR is the only kind of envelope generator, and could only ever - control the volume. While it's simple for new users, it's not quite - right.

    ADSR

    A type of envelope generator that allows you to control the + synthesizers, drums, or samplers. The definitions here provide more + detail and explanation than the simplified ones in the text. For + example, the text of the manual would have you believe that an ADSR is + the only kind of envelope generator and could only ever control the + volume. While the simplified definitions help new users start using + Hydrogen quickly, they can lack the nuances presented here.

    ADSR

    A type of envelope generator that allows you to control the Attack, Decay, Sustain, and @@ -1178,7 +1194,12 @@ guitar), it sounds like someone is putting a blanket over the speaker. The higher frequencies are being attenuated above 30 Hz.

    See Also Filter, High-Pass Filter, Low-Pass Filter, Resonance Filter.

    Decay

    After reaching full velocity from the attack, this is the amount of time to turn the parameter down from full - velocity to the sustain level.

    See Also ADSR.

    Envelope Generator

    A way to control (change) a parameter over time as a response to + velocity to the sustain level.

    See Also ADSR.

    DC-offsety

    DC offset, or DC coefficient is the mean value of the wavefor.m

    DC offset is usually undesirable. For example, in audio processing, a + sound that has DC offset will not be at its loudest possible volume when + normalized (because the offset consumes headroom), and this problem can + possibly extend to the mix as a whole, since a sound with DC offset and a sound + without DC offset will have DC offset when mixed. It may also cause other artifacts + depending on what is being done with the signal.

    Envelope Generator

    A way to control (change) a parameter over time as a response to triggering, holding, and releasing a note.

    Did your eyes just glaze over? Let's try again:

    Imagine that you're playing a note on the keyboard and you have your other hand on a knob (volume, filter cutoff, etc.). As you play the note, you twist the knob (often up, then down... or down, then up). Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/doc/MidiInstrumentMapping.ods and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/doc/MidiInstrumentMapping.ods differ diff -Nru hydrogen-0.9.6~beta1/data/hydrogen.default.conf hydrogen-0.9.6~beta2/data/hydrogen.default.conf --- hydrogen-0.9.6~beta1/data/hydrogen.default.conf 2011-09-17 17:03:54.000000000 +0000 +++ hydrogen-0.9.6~beta2/data/hydrogen.default.conf 2012-05-25 12:19:45.000000000 +0000 @@ -13,8 +13,8 @@ true false false - 400 - true + 400 + false true true false Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/i18n/hydrogen.de.qm and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/i18n/hydrogen.de.qm differ diff -Nru hydrogen-0.9.6~beta1/data/i18n/hydrogen.de.ts hydrogen-0.9.6~beta2/data/i18n/hydrogen.de.ts --- hydrogen-0.9.6~beta1/data/i18n/hydrogen.de.ts 2011-09-12 11:54:45.000000000 +0000 +++ hydrogen-0.9.6~beta2/data/i18n/hydrogen.de.ts 2012-05-25 12:19:45.000000000 +0000 @@ -620,14 +620,14 @@ Director Director - Dirigent + Dirigent Director_UI Dialog - Dialog + Dialog @@ -735,15 +735,15 @@ Export to a single track - + Als einzelne Spur exportieren Export to seperate tracks - + Mehrspur Export Both - + Beides This version of hydrogen is not able to export songs with tempo changes. If you proceed, the song will be exported without tempo changes. @@ -790,23 +790,23 @@ 22050 - 22050 + 22050 44100 - 44100 + 44100 48000 - 48000 + 48000 96000 - 96000 + 96000 192000 - 192000 + 192000 SampleDepth in Bit: @@ -814,19 +814,19 @@ 8 - 8 + 8 16 - 16 + 16 24 - 24 + 24 32 - 32 + 32 Templates: @@ -834,43 +834,43 @@ WAV in CD quality "44,1kHz, 16 bit PCM" - + WAV in CD Qualität "44,1kHz, 16 bit PCM" WAV in ADAT quality "48 kHz, 16 bit PCM" - + WAV in ADAT Qualität "48 kHz, 16 bit PCM" WAV in better quality "48 kHz, 24 bit PCM" - + WAV in besserer Qualität "48 kHz, 24 bit PCM" WAV LOFI "22.05kHz, 8 bit PCM - + WAV in geringster Qualität "22.05kHz, 8 bit PCM WAV best Mixdown quality "96 kHz, 32 bit PCM" - + WAV beste Qualität "96 kHz, 32 bit PCM" AIFF in CD quality "41 kHz, 16 bit PCM" - + AIFF in CD Qualität "41 kHz, 16 bit PCM" AIFF in ADAT quality "48 kHz, 16 bit PCM" - + AIFF in ADAT Qualität "48 kHz, 16 bit PCM" AIFF in better quality "48 kHz, 24 bit PCM" - + AIFF in besserer Qualität "48 kHz, 24 bit PCM" FLAC lossless compressor in good quality "48 kHz" - + FLAC verlustfreie Kompression in guter Qualität "48 kHz" OGG Vorbis loosely compressed in good quality "VBR" - + OGG Vorbis gering komprimiert in guter Qualität "VBR" @@ -895,21 +895,21 @@ H2Core::SongEditorPanelBpmWidget BPM - + BPM H2Core::SongEditorPanelTagWidget Tag - + Tag H2Core::SoundLibraryPropertiesDialog SoundLibrary Properties - Soundlibrary Eigenschaften + Soundlibrary Eigenschaften &Ok @@ -921,12 +921,12 @@ This is not possible, you can only save changes inside instruments to the current loaded sound library - Nicht möglich, es lassen sich nur Ă„nderungen an Instrumenten innerhalb der aktuell verwendeten Soundlibrary speichern. + Nicht möglich, es lassen sich nur Ă„nderungen an Instrumenten innerhalb der aktuell verwendeten Soundlibrary speichern. Warning! Changing the drumkit name will result in creating a new drumkit with this name. Are you sure? - Achtung! Bei Ă„nderungen des Drumkit-Namens wird ein neues Drumkit dieses Namens erstellt. + Achtung! Bei Ă„nderungen des Drumkit-Namens wird ein neues Drumkit dieses Namens erstellt. Sind sie sicher? @@ -1010,7 +1010,7 @@ Auto-Stop-Note - + Auto-Stop-Note @@ -1729,15 +1729,15 @@ Loaded Soundlibrary - Geladene Klangbibliothek + Geladene Klangbibliothek Midi keyboard or computer keys play whole drumset or single instruments - Midi-Tatertur oder Tastertur anschläge spielen die geladene Klangbibliothek im Grund-Ton oder das ausgewählte Instrument mit Tonhöhen-Veränderung + Midi-Tastertur oder Tasterturanschläge spielen die geladene Klangbibliothek im Grund-Ton oder das ausgewählte Instrument mit Tonhöhen-Veränderung NoteKey - Note + Note destructive mode pre delete settings @@ -1749,7 +1749,7 @@ Piano - + Piano Show piano roll editor @@ -2284,15 +2284,15 @@ Driver restart required. Restart driver? - + Treiber-Neustart notwendig. Soll der Treiber nun neu gestartet werden? &Ok - &OK + &OK &Cancel - &Abbrechen + &Abbrechen @@ -2515,7 +2515,7 @@ Audio output details - + Details des Audio Ausgangs Post-Fader @@ -2527,7 +2527,7 @@ Track output - Spur Ausgang + Spur Ausgang Use lash @@ -2535,35 +2535,35 @@ first step, adjust timing mismatch between controller/keyboard trigger latency and computed bpm - Zuerst, justiere die Zeitdifferenz zwischen Tastatur-/Controller-Anschlägen und den von Hydrogen errechneten BPM-Werten + Zuerst, justiere die Zeitdifferenz zwischen Tastatur-/Controller-Anschlägen und den von Hydrogen errechneten BPM-Werten Beat counter drift compensation in 1/10 ms - Takt-Zähler-Kompensation in 1/10 ms + Takt-Zähler-Kompensation in 1/10 ms second step, adjust offset between last controller/keybord trigger and the deferred sequencer startup - Zweitens, justiere die Zeitdifferenz zwischen letzten Tastatur/Controller Anschlag und dem zeitverzögerten Sequenzer Start. + Zweitens, justiere die Zeitdifferenz zwischen letzten Tastatur/Controller Anschlag und dem zeitverzögerten Sequenzer Start. Beat counter start offset in ms - Takt-Zähler-Startverzögerung in ms + Takt-Zähler-Startverzögerung in ms create per-instrument outputs - + Ausgänge pro Spur erstellen Path to the Rubberband command-line utility - + Pfad zum Rubberband Kommondozeilenprogram Maximum number of bars - + Maximale Anzahl an Takten &Reopen last used playlist - + &Zuletzt benutzte Playlist wiederherstellen @@ -2571,21 +2571,21 @@ Unsaved changes left. This changes will be lost. Are you sure? - Es sind noch nicht gespeicherte änderungen vorhanden. Diese Ă„nderungen werden verloren gehen. + Es sind noch nicht gespeicherte änderungen vorhanden. Diese Ă„nderungen werden verloren gehen. Sind sie sicher? &Ok - &OK + &OK &Cancel - &Abbrechen + &Abbrechen Close dialog! maybe there is some unsaved work on sample. Are you sure? - SchlieĂźe Fenster. Möglicherweise sind noch ungespeicherte änderungen an diesen Sampel. + SchlieĂźe Fenster. Möglicherweise sind noch ungespeicherte änderungen an diesen Sampel. Sind sie sicher? @@ -2593,71 +2593,71 @@ SampleEditor_UI Dialog - Dialog + Dialog P&lay original sample - Spie&le Original + Spie&le Original &Apply Changes - &Anwenden + &Anwenden &Close - &SchlieĂźen + &SchlieĂźen Adjust sample start frame - Justiere Sampel-Start + Justiere Sample-Start Adjust sample loop begin frame - Justieren den Sampel Loop-Anfang + Justiere den Sample Loop-Anfang set processing - Sampleverarbeitung einstellen + Sampleverarbeitung einstellen forward - vörwärts + vorwärts reverse - rĂĽckwärts + rĂĽckwärts pingpong - hin und her + hin und her loops - Wiederholungen + Wiederholungen Adjust sample end & loop end frame - Justiere Sampel ende & Wiederholungs-Ende + Justiere Sample ende & Wiederholungs-Ende &Play - S&piele + &Abspielen new sample length: - Neue Sempellänge: + Neue Samplelänge: fade-out type - Art der Ausblendung + Art der Ausblendung volume - + Lautstärke panorama - + Panorama Sample length to beat: @@ -2669,155 +2669,155 @@ 1/64 - 1/64 + 1/64 1/32 - 1/32 + 1/32 1/16 - 1/16 + 1/16 1/8 - 1/8 + 1/8 1/4 - 1/4 + 1/4 1/2 - 1/2 + 1/2 1 - 1 + 1 2 - 2 + 2 3 - 3 + 3 4 - 4 + 4 5 - 5 + 5 6 - 6 + 6 7 - 7 + 7 8 - 8 + 8 9 - 9 + 9 10 - 10 + 10 11 - 11 + 11 12 - 12 + 12 13 - 13 + 13 14 - 14 + 14 15 - 15 + 15 16 - 16 + 16 17 - 17 + 17 18 - 18 + 18 19 - 19 + 19 20 - 20 + 20 21 - 21 + 21 22 - 22 + 22 23 - 23 + 23 24 - 24 + 24 25 - 25 + 25 26 - 26 + 26 27 - 27 + 27 28 - 28 + 28 29 - 29 + 29 30 - 30 + 30 31 - 31 + 31 32 - 32 + 32 Pitch the sample in semitones, cents @@ -2846,7 +2846,7 @@ 0 - 0 + 0 Start @@ -2876,7 +2876,7 @@ End - + Ende "Rubberband Audio Processor" : Change the tempo (sample length) and pitch of audio. @@ -2973,11 +2973,11 @@ Enable time line edit - + Timeline Editor aktivieren Pattern %1 - + Pattern %1 @@ -3020,11 +3020,11 @@ Cancel - Abbrechen + Abbrechen Ok - OK + OK @@ -3103,11 +3103,11 @@ &Ok - &OK + &OK &Cancel - &Abbrechen + &Abbrechen @@ -3434,7 +3434,7 @@ Please supply at least a valid name - + Bitte gĂĽltigen Dateinamen angeben! @@ -3486,15 +3486,15 @@ VirtualPatternDialog_UI Dialog - Dialog + Dialog OK - OK + OK Cancel - Abbrechen + Abbrechen Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/i18n/hydrogen.fr.qm and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/i18n/hydrogen.fr.qm differ diff -Nru hydrogen-0.9.6~beta1/data/i18n/hydrogen.fr.ts hydrogen-0.9.6~beta2/data/i18n/hydrogen.fr.ts --- hydrogen-0.9.6~beta1/data/i18n/hydrogen.fr.ts 2011-09-12 11:54:45.000000000 +0000 +++ hydrogen-0.9.6~beta2/data/i18n/hydrogen.fr.ts 2012-05-25 12:19:45.000000000 +0000 @@ -5,7 +5,7 @@ AboutDialog <b>Project page</b><br> - <b>Page de projet</b><br> + <b>Page du projet</b><br> About @@ -25,7 +25,7 @@ Translator:%1Alessandro Cominu - Traducteur:%1Alessandro Cominu + Traducteurs:%1Yan Morin, Olivier Humbert, DYP et Fred Courchesne @@ -405,7 +405,8 @@ <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#ffffff;">consider it more useful to permit linking proprietary applications with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#ffffff;">library. If this is what you want to do, use the GNU Library General</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#ffffff;">Public License instead of this License.</p></body></html> - + Ne pas traduire la licence + @@ -518,7 +519,7 @@ Samplerate: %1 - Taux d'Ă©chantillonage: %1 + FrĂ©quence: %1 Hz s @@ -538,15 +539,15 @@ Sample length: - Taille d'Ă©chantillon: + DurĂ©e: Please do not preview samples which are longer than 10 minutes! - Merci de ne pas faire des previews sur des Ă©chantillons de plus de 10 minutes ! + Merci de ne pas faire des previews sur des Ă©chantillons de plus de 10 minutes! Sample length: - Taille d'Ă©chantillon: + DurĂ©e: @@ -561,7 +562,7 @@ Samplerate: - Taux d'Ă©chantillonnage: + FrĂ©quence: Size: @@ -569,7 +570,7 @@ Length: - Longueur: + DurĂ©e: Pla&y samples by clicking @@ -585,11 +586,11 @@ &Play Sample - Jouer Ă©chantillon (&P) + &Jouer l'Ă©chantillon &Filename to instrument name - + &Nom de fichier comme nom d'instrument Open @@ -601,7 +602,7 @@ &Stop - &Stop + &ArrĂŞter View hidden folders @@ -613,21 +614,21 @@ Set automatic velocity - RĂ©gler automatiquement la vĂ©locitĂ© + RĂ©glage de vĂ©locitĂ© auto Director Director - Conducteur + Directeur Director_UI Dialog - Dialogue + Dialogue @@ -723,29 +724,29 @@ Export failed! - Export ratĂ©! + Échec de l'exportation! The file %1 exists. Overwrite the existing file? - Le fichier %1 existe. -Remplacer le fichier existant ? + Le fichier %1 existe dĂ©jĂ . +Écraser le fichier existant ? Export to a single track - + Mode piste unique Export to seperate tracks - Exporter en pistes sĂ©parĂ©es + Mode multipistes Both - + Mode combinĂ© This version of hydrogen is not able to export songs with tempo changes. If you proceed, the song will be exported without tempo changes. - + Cette version d'Hydrogen n'est pas capable d'exporter des morceaux comportant des changements de tempo. Si vous poursuivez, ce morceau sera exporter sans changement de tempo. @@ -784,7 +785,8 @@ Samplerate in Hz: - Taux d'Ă©chantillonnage en Hz: + L'ancienne Ă©tiquette "Taux d'Ă©chantillonnage en Hz:" Ă©tait beaucoup trop longue + FrĂ©quence: 22050 @@ -808,7 +810,8 @@ SampleDepth in Bit: - Profondeur d'Ă©chantillonnage en Bit: + L'ancienne Ă©tiquette "Profondeur d'Ă©chantillonnage en Bit:" Ă©tait beaucoup trop longue + RĂ©solution: 8 @@ -828,7 +831,7 @@ Templates: - Gabarits: + Format: WAV in CD quality "44,1kHz, 16 bit PCM" @@ -1068,7 +1071,7 @@ Sound library - Bibliothèque de sons + Bibliothèque @@ -1118,7 +1121,7 @@ Remove FX - + Retirer l'effet @@ -1299,7 +1302,7 @@ Hydrogen Ready. - Hydrogen est prĂŞt. + Hydrogen est pret. &Save @@ -1343,11 +1346,11 @@ Open &Demo - Ouvrir une &dĂ©mo... + Ouvrir un &demo Open &recent - Ouvrir un fichier rĂ©&cent + Ouvrir un fichier rĂ©&cent... Save &as... @@ -1379,7 +1382,7 @@ &Cancel - Annuler (&C) + &Annuler Unknown audio driver @@ -1439,7 +1442,7 @@ Song saved. - &Le morceau a Ă©tĂ© enregistrĂ©. + Morceau enregistrĂ©. Unknown error %1 @@ -1471,7 +1474,7 @@ Hydrogen Pattern (*.h2pattern) - Motif d'hydrogen (*.h2pattern) + Motif Hydrogen (*.h2pattern) Save Pattern as ... @@ -1511,7 +1514,7 @@ &Clear all - E&ffacer tout + Effacer &tout &Save library @@ -1519,15 +1522,15 @@ &Export library - &Exporter la bibliothèque... + &Exporter une bibliothèque... Playlist &editor - Navigateur de la liste de lecture... + &Navigateur de liste de lecture... &Import library - &Importer la bibliothèque... + &Importer une bibliothèque... @@ -1558,7 +1561,7 @@ Director - Conducteur + &Directeur @@ -1749,7 +1752,7 @@ Loaded Soundlibrary - Charger la bibliothèque de sons + Bibliothèque chargĂ©e Quantize incoming keyboard/midi events = Off @@ -1789,8 +1792,7 @@ Right click into pattern editor add note-off-note or edit note-length, velocity or pan - note-off-note ? c'est quoi ? - Un click droit dans l'Ă©diteur de motif ajoute une note-off-note ou Ă©dite la profondeur de note; la vĂ©locitĂ© ou le panoramique + Un click droit dans l'Ă©diteur de motif ajoute une note off ou Ă©dite la profondeur de note, la vĂ©locitĂ© ou la balance @@ -1953,7 +1955,7 @@ Mixer - Table de mixage + Mixage Show Instrument Rack @@ -1961,7 +1963,7 @@ Instrument rack - Liste des instruments + Instruments Pause. @@ -2045,15 +2047,15 @@ Recalculate Rubberband modified samples if bpm will change - Recalcule l'Ă©chantillon modifiĂ© par Rubberband si les bpm changent + Recalcule l'Ă©chantillon modifiĂ© par Rubberband si le bpm change Recalculate all samples using Rubberband ON - Recalcule tous les Ă©chantillons qui utilisent Rubberband ON + Recalcule tous les Ă©chantillons qui utilisent Rubberband Recalculate all samples using Rubberband OFF - Recalcule tous les Ă©chantillons qui utilisent Rubberband OFF + Recalcule tous les Ă©chantillons qui n'utilisent pas Rubberband @@ -2076,7 +2078,7 @@ No Song selected! - Aucun morceau de sĂ©lectionnĂ© + Aucun morceau n'est sĂ©lectionnĂ©! Load Playlist @@ -2111,8 +2113,9 @@ Do not use a console based Editor Sorry, but this will not work for the moment. Aucun Ă©diteur par dĂ©faut de rĂ©gler. Veuillez rĂ©gler l'Ă©diteur par dĂ©faut. + N'utiliser pas un Ă©diteur en mode console. -DĂ©solĂ©, mais un Ă©diteur en mode console ne fonctionne pas prĂ©sentement. +DĂ©solĂ©, mais un Ă©diteur en mode console ne fonctionnera pas prĂ©sentement. Set your Default Editor @@ -2120,7 +2123,7 @@ No Script selected! - Aucun script de sĂ©lectionnĂ© + Aucun script de sĂ©lectionnĂ©! Error loading song. @@ -2152,31 +2155,31 @@ &Playlist - Liste de lecture (&P) + &Liste de lecture Add song to Play&list - Ajouter le morceau Ă  la &Liste de lecture + &Ajouter un morceau Ă  la &liste Add &current song to Playlist - Ajouter &ce morceau Ă  la Liste de Lecture + Ajouter &ce morceau Ă  la liste &Remove selected song from Playlist - Enleve&r le morceau sĂ©lectionnĂ© de la Liste de Lecture + &Retirer le morceau sĂ©lectionnĂ© &Open Playlist - &Ouvrir la Liste de Lecture + &Ouvrir une liste de lecture &Save Playlist - &Sauver la Liste de Lecture + Enregi&strer Save Playlist &as - S&auver la Liste de Lecture comme + Enregistrer so&us... &Scripts @@ -2184,19 +2187,19 @@ &Add Script to selected song - &Ajouter un Script Ă  la chanson sĂ©lectionnĂ©e + &Ajouter un script au morceau sĂ©lectionnĂ© &Edit selected Script - Édit&er le Script sĂ©lectionnĂ© + Édit&er le script sĂ©lectionnĂ© &Remove selected Script - Enleve&r le Script sĂ©lectionnĂ© + &Retirer le script sĂ©lectionnĂ© &Create a new Script - &CrĂ©er un nouveau Script + &CrĂ©er un nouveau script Rewind @@ -2228,23 +2231,23 @@ Remove all songs from &Playlist - Efface tous les morceaux depuis la Liste de Lecture (&P) + &Vider la liste de lecture Playlist Browser - + Navigateur de liste de lecture No song selected! - + Auncun morceau sĂ©lectionnĂ©! Playlist: set song no. %1 - + Liste: choisir le morceau #%1 no Script - + Aucun script @@ -2608,12 +2611,12 @@ &Cancel - Annuler (&C) + &Annuler Close dialog! maybe there is some unsaved work on sample. Are you sure? - Fermeture du dialogue! Peut ĂŞtre y a-t'il du travail non sauvegardĂ© sur l'Ă©chantillon. + Fermeture de la boite de dialogue! Peut ĂŞtre y a-t'il du travail non sauvegardĂ© sur l'Ă©chantillon. ĂŠtes-vous sĂ»r ? @@ -2637,11 +2640,11 @@ Adjust sample start frame - + Ajuster le point de dĂ©part de l'Ă©chantillon Adjust sample loop begin frame - + Ajuster le dĂ©but de la boucle de l'Ă©chantillon set processing @@ -2665,7 +2668,7 @@ Adjust sample end & loop end frame - + Ajuster le point d'arrivĂ© de l'Ă©chantillon &Play @@ -2702,7 +2705,20 @@ <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">more informations about you can find here:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.breakfastquay.com/rubberband/ "><span style=" text-decoration: underline; color:#0000ff;">http://www.breakfastquay.com/rubberband/ </span></a></p></body></html> - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;">Niveaux de "croustillance" : </p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"> 0 Ă©quivaut Ă  --no-transients --no-lamination --window-long</p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"> 1 Ă©quivalent Ă  --no-transients --no-lamination</p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"> 2 Ă©quivalent Ă  --no-transients</p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"> 3, Ă©quivalent Ă  --bl-transients</p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"> 4 options de traitement par dĂ©faut </p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"> 5 Ă©quivalent Ă  --no-lamination --window-short (peut-ĂŞtre bon pour la batterie) </p> +<p style="-qt-paragraph-type:empty;margin: 0px;-qt-block-indent:0;text-indent:0px;"></p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;">Vous pouvez trouver plus d'informations ici (en anglais seulement): </p> +<p style="margin:0px;-qt-block-indent:0;text-indent:0px;"><a href="http://www.breakfastquay.com/rubberband/"><span style="text-decoration: underline; color:#0000ff;">http://www.breakfastquay.com/rubberband/</span></a></p></body></html> 0 @@ -2878,11 +2894,11 @@ Start - + DĂ©part Loop - + Boucle <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> @@ -2904,15 +2920,15 @@ End - + Fin "Rubberband Audio Processor" : Change the tempo (sample length) and pitch of audio. - + "Processeur audio Rubberband" : Modifie le tempo et la hauteur de l'Ă©chantillon. Pitch (Semitone,Cent) - + Hauteur (Demi-ton, Pourcent) @@ -3109,7 +3125,7 @@ Hydrogen Pattern (*.h2pattern) - Motif d'hydrogen (*.h2pattern) + Motif Hydrogen (*.h2pattern) Virtual Pattern @@ -3126,8 +3142,7 @@ The pattern-file exists. Overwrite the existing pattern? - Le fichier de motif existe. -Remplacer le motif existant ? + Le fichier de motif existe. Écraser le motif existant ? &Ok @@ -3135,7 +3150,7 @@ &Cancel - Annuler (&C) + &Annuler @@ -3161,7 +3176,7 @@ &Cancel - Annuler (&C) + &Annuler Form1 @@ -3203,7 +3218,7 @@ Browse - Naviguer + Explorer Export @@ -3242,7 +3257,7 @@ Downloading SoundLibrary... - TĂ©lĂ©chargement de la bibliothèque de sons. + TĂ©lĂ©chargement de la bibliothèque de sons... Import drumkit @@ -3321,7 +3336,7 @@ License... - Licence + Licence... Edit server list @@ -3366,7 +3381,7 @@ &Cancel - Annuler (&C) + &Annuler Songs @@ -3423,7 +3438,7 @@ Save changes made to instruments into sound library - Enregistrer les changements des instruments dans la bibliothèque de sons + Enregistrer les changements appliquĂ©s aux instruments dans la bibliothèque de sons @@ -3502,7 +3517,7 @@ SoundLibraryTree Sound library - Bibliothèque de sons + Bibliothèque Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/patternEditor/background_rec-new.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/patternEditor/background_rec-new.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/patternEditor/btn_drum_piano_off.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/patternEditor/btn_drum_piano_off.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/patternEditor/btn_drum_piano_on.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/patternEditor/btn_drum_piano_on.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/playerControlPanel/background_Control.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/playerControlPanel/background_Control.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/playerControlPanel/statusLED_off.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/playerControlPanel/statusLED_off.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/playerControlPanel/statusLED_on.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/playerControlPanel/statusLED_on.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/skin_btn_off.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/skin_btn_off.png differ Binary files /tmp/3DHNB5OL3x/hydrogen-0.9.6~beta1/data/img/gray/skin_btn_over.png and /tmp/iBeviblT_a/hydrogen-0.9.6~beta2/data/img/gray/skin_btn_over.png differ diff -Nru hydrogen-0.9.6~beta1/data/xsd/drumkit.xsd hydrogen-0.9.6~beta2/data/xsd/drumkit.xsd --- hydrogen-0.9.6~beta1/data/xsd/drumkit.xsd 2011-07-21 20:13:55.000000000 +0000 +++ hydrogen-0.9.6~beta2/data/xsd/drumkit.xsd 2012-05-25 12:19:45.000000000 +0000 @@ -66,7 +66,7 @@ - + diff -Nru hydrogen-0.9.6~beta1/debian/changelog hydrogen-0.9.6~beta2/debian/changelog --- hydrogen-0.9.6~beta1/debian/changelog 2012-03-16 10:03:35.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/changelog 2012-07-12 22:20:04.000000000 +0000 @@ -1,15 +1,40 @@ -hydrogen (0.9.6~beta1-1ubuntu2) precise; urgency=low +hydrogen (0.9.6~beta2-1~12.04) precise; urgency=medium - * No-change rebuild against libarchive12. + * Import from debian wheezy. - -- Martin Pitt Fri, 16 Mar 2012 11:03:35 +0100 + -- DNS777 Thu, 12 Jul 2012 15:00:00 +0000 -hydrogen (0.9.6~beta1-1ubuntu1) precise; urgency=low +hydrogen (0.9.6~beta2-1) unstable; urgency=low - * Replace rsvg with rsvg-convert in debian/rules to prevent FTBFS with - newer librsvg2-bin (LP: #935170) + * Team upload. + * New upstream release. + * Refresh patches. + * Don't install extra/serverTools directory, it is no longer provided. + * Fix off-by-one error in JACK MIDI. + Thanks to Roland Mas for the patch! (Closes: #661725) + + -- Alessio Treglia Tue, 12 Jun 2012 11:50:06 +0200 + +hydrogen (0.9.6~beta1-3) unstable; urgency=low + + * Team upload. + + [ Adrian Knoth ] + * Add patch to fix FTBFS with gcc-4.7 (Closes: #667203). + + [ Alessio Treglia ] + * Update debian/copyright to machine-readable format. + * Bump Standards-Version. + * Regenerate debian/control. + + -- Alessio Treglia Tue, 08 May 2012 11:28:41 -0700 + +hydrogen (0.9.6~beta1-2) unstable; urgency=low + + * Replace rsvg with rsvg-convert to convert SVG to PNG image (LP: #935170): + - Future versions of librsvg won't provide the 'rsvg' tool anymore. - -- Alessio Treglia Sat, 18 Feb 2012 16:43:33 +0100 + -- Alessio Treglia Sat, 18 Feb 2012 17:46:48 +0100 hydrogen (0.9.6~beta1-1) unstable; urgency=low diff -Nru hydrogen-0.9.6~beta1/debian/control hydrogen-0.9.6~beta2/debian/control --- hydrogen-0.9.6~beta1/debian/control 2012-02-18 15:44:28.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/control 2012-06-12 09:49:47.000000000 +0000 @@ -1,12 +1,13 @@ Source: hydrogen Section: sound Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Multimedia Maintainers -Uploaders: Jonas Smedegaard -Build-Depends: devscripts (>= 2.10.7~), - cdbs (>= 0.4.73~), - debhelper (>= 6), +Maintainer: Debian Multimedia Maintainers +Uploaders: + Jonas Smedegaard +Build-Depends: + cdbs (>= 0.4.70~), + devscripts, + debhelper, dh-buildinfo, cmake, libqt4-dev, @@ -26,15 +27,19 @@ libportmidi-dev, librsvg2-bin, netpbm -Standards-Version: 3.9.2 +Standards-Version: 3.9.3 Homepage: http://www.hydrogen-music.org/ Vcs-Git: git://git.debian.org/git/pkg-multimedia/hydrogen.git Vcs-Browser: http://git.debian.org/?p=pkg-multimedia/hydrogen.git;a=summary Package: hydrogen Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Recommends: hydrogen-drumkits, rubberband-cli +Depends: + ${misc:Depends}, + ${shlibs:Depends} +Recommends: + hydrogen-drumkits, + rubberband-cli Description: advanced drum machine/step sequencer Hydrogen is an advanced drum machine. It's main goal is to bring professional yet simple and intuitive pattern-based drum programming. diff -Nru hydrogen-0.9.6~beta1/debian/control.in hydrogen-0.9.6~beta2/debian/control.in --- hydrogen-0.9.6~beta1/debian/control.in 2012-02-18 15:44:28.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/control.in 2012-05-08 18:22:14.000000000 +0000 @@ -1,19 +1,24 @@ Source: hydrogen Section: sound Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Multimedia Maintainers -Uploaders: Jonas Smedegaard -Build-Depends: @cdbs@ -Standards-Version: 3.9.2 +Maintainer: Debian Multimedia Maintainers +Uploaders: + Jonas Smedegaard +Build-Depends: + @cdbs@ +Standards-Version: 3.9.3 Homepage: http://www.hydrogen-music.org/ Vcs-Git: git://git.debian.org/git/pkg-multimedia/hydrogen.git Vcs-Browser: http://git.debian.org/?p=pkg-multimedia/hydrogen.git;a=summary Package: hydrogen Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Recommends: hydrogen-drumkits, rubberband-cli +Depends: + ${misc:Depends}, + ${shlibs:Depends} +Recommends: + hydrogen-drumkits, + rubberband-cli Description: advanced drum machine/step sequencer Hydrogen is an advanced drum machine. It's main goal is to bring professional yet simple and intuitive pattern-based drum programming. diff -Nru hydrogen-0.9.6~beta1/debian/copyright hydrogen-0.9.6~beta2/debian/copyright --- hydrogen-0.9.6~beta1/debian/copyright 2012-01-27 09:39:22.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/copyright 2012-05-08 18:22:19.000000000 +0000 @@ -1,16 +1,18 @@ -Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?rev=173 +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Hydrogen Upstream-Contact: Alessandro Cominu (Comix) Source: http://sourceforge.net/projects/hydrogen/ Files: * -Copyright: 2002-2008, Alessandro Cominu (Comix) +Copyright: + 2002-2008, Alessandro Cominu (Comix) 2002-2008, Jonathan Dempsey 2008, Sebastian Moors License: GPL-2+ Files: */ladspa.h -Copyright: 2000-2002, Richard W.E. Furse +Copyright: + 2000-2002, Richard W.E. Furse 2000-2002, Paul Barton-Davis 2000-2002, Stefan Westerfeld License: LGPL-2.1+ diff -Nru hydrogen-0.9.6~beta1/debian/patches/09_portaudio_v2.patch hydrogen-0.9.6~beta2/debian/patches/09_portaudio_v2.patch --- hydrogen-0.9.6~beta1/debian/patches/09_portaudio_v2.patch 2012-01-27 01:29:37.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/patches/09_portaudio_v2.patch 2012-06-12 09:35:50.000000000 +0000 @@ -5,7 +5,7 @@ --- hydrogen.orig/src/core/src/IO/PortAudioDriver.h +++ hydrogen/src/core/src/IO/PortAudioDriver.h -@@ -28,6 +28,11 @@ +@@ -30,6 +30,11 @@ #ifdef H2CORE_HAVE_PORTAUDIO diff -Nru hydrogen-0.9.6~beta1/debian/patches/1007_off_by_one_in_jackmidi.patch hydrogen-0.9.6~beta2/debian/patches/1007_off_by_one_in_jackmidi.patch --- hydrogen-0.9.6~beta1/debian/patches/1007_off_by_one_in_jackmidi.patch 1970-01-01 00:00:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/patches/1007_off_by_one_in_jackmidi.patch 2012-06-12 09:42:54.000000000 +0000 @@ -0,0 +1,39 @@ +Description: Fix off-by-one error in JACK MIDI + Fixed bug whereby a MIDI event is only sent when there is another + one queued. +Author: Roland Mas +Bug-Debian: http://bugs.debian.org/661725 +--- + src/core/src/IO/jack_midi_driver.cpp | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- hydrogen.orig/src/core/src/IO/jack_midi_driver.cpp ++++ hydrogen/src/core/src/IO/jack_midi_driver.cpp +@@ -234,11 +234,12 @@ JackMidiDriver::JackMidiRead(jack_nframe + if (buffer == NULL) + break; + +- memcpy(buffer, jack_buffer + (4 * rx_in_pos) + 1, len); + t++; + rx_in_pos++; + if (rx_in_pos >= JACK_MIDI_BUFFER_MAX) + rx_in_pos = 0; ++ ++ memcpy(buffer, jack_buffer + (4 * rx_in_pos) + 1, len); + } + unlock(); + } +@@ -394,6 +395,13 @@ void JackMidiDriver::handleQueueNote(Not + if (vel < 0 || vel > 127) + return; + ++ buffer[0] = 0x80 | channel; /* note off */ ++ buffer[1] = key; ++ buffer[2] = 0; ++ buffer[3] = 0; ++ ++ JackMidiOutEvent(buffer, 3); ++ + buffer[0] = 0x90 | channel; /* note on */ + buffer[1] = key; + buffer[2] = vel; diff -Nru hydrogen-0.9.6~beta1/debian/patches/ftbfs-gcc-4.7.diff hydrogen-0.9.6~beta2/debian/patches/ftbfs-gcc-4.7.diff --- hydrogen-0.9.6~beta1/debian/patches/ftbfs-gcc-4.7.diff 1970-01-01 00:00:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/patches/ftbfs-gcc-4.7.diff 2012-06-12 09:39:50.000000000 +0000 @@ -0,0 +1,40 @@ +Description: Fix missing #includes to avoid build failures with GCC 4.7 +Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=667203 +Author: Matthias Klose +Forwarded: no +--- + src/core/src/IO/portmidi_driver.cpp | 1 + + src/gui/src/MainForm.cpp | 1 + + src/gui/src/SongEditor/SongEditor.cpp | 1 + + 3 files changed, 3 insertions(+) + +--- hydrogen.orig/src/core/src/IO/portmidi_driver.cpp ++++ hydrogen/src/core/src/IO/portmidi_driver.cpp +@@ -32,6 +32,7 @@ + #ifdef WIN32 + #include + #endif ++#include + + #ifdef H2CORE_HAVE_PORTMIDI + +--- hydrogen.orig/src/gui/src/SongEditor/SongEditor.cpp ++++ hydrogen/src/gui/src/SongEditor/SongEditor.cpp +@@ -21,6 +21,7 @@ + */ + + #include ++#include + #include + #include + +--- hydrogen.orig/src/gui/src/MainForm.cpp ++++ hydrogen/src/gui/src/MainForm.cpp +@@ -20,6 +20,7 @@ + * + */ + ++#include + #include + #include + #include diff -Nru hydrogen-0.9.6~beta1/debian/patches/series hydrogen-0.9.6~beta2/debian/patches/series --- hydrogen-0.9.6~beta1/debian/patches/series 2012-01-27 09:15:11.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/patches/series 2012-06-12 09:41:35.000000000 +0000 @@ -2,3 +2,5 @@ 1001_rubberband_path.patch 1005_name_shouldnt_repeat_genericname.patch 1006_porttime.patch +ftbfs-gcc-4.7.diff +1007_off_by_one_in_jackmidi.patch diff -Nru hydrogen-0.9.6~beta1/debian/rules hydrogen-0.9.6~beta2/debian/rules --- hydrogen-0.9.6~beta1/debian/rules 2012-02-18 16:26:51.000000000 +0000 +++ hydrogen-0.9.6~beta2/debian/rules 2012-06-12 10:41:16.000000000 +0000 @@ -34,7 +34,6 @@ export QTDIR=/usr/share/qt4 DEB_INSTALL_MANPAGES_hydrogen = debian/hydrogen.1 -DEB_INSTALL_EXAMPLES_hydrogen = extra/serverTools # Put aside upstream-shipped autogenerated files during build upstreamtmpfiles = $(wildcard data/doc/*.html data/doc/*.docbook) diff -Nru hydrogen-0.9.6~beta1/DEVELOPERS hydrogen-0.9.6~beta2/DEVELOPERS --- hydrogen-0.9.6~beta1/DEVELOPERS 2011-05-12 18:51:07.000000000 +0000 +++ hydrogen-0.9.6~beta2/DEVELOPERS 2012-05-25 12:19:45.000000000 +0000 @@ -56,15 +56,14 @@ release. Remember, after tagging the release you may not commit changes to the tag. - svn cp http://svn.assembla.com/svn/hydrogen/trunk \ - http://svn.assembla.com/svn/hydrogen/tags/0.9.4 + git tag -a 0.9.4 -m "Tagging 0.9.4" 9. If this is a major release (e.g. 0.9.4), then make a branch for maintenance patches for your release. If this is a maintenance release (e.g. 0.9.4.1) then skip this step. - svn cp http://svn.assembla.com/svn/hydrogen/trunk \ - http://svn.assembla.com/svn/hydrogen/branches/0.9.4 + git branch 0.9.4 + git push origin 0.9.4 10. Make announcements. diff -Nru hydrogen-0.9.6~beta1/INSTALL.txt hydrogen-0.9.6~beta2/INSTALL.txt --- hydrogen-0.9.6~beta1/INSTALL.txt 2011-07-03 11:21:31.000000000 +0000 +++ hydrogen-0.9.6~beta2/INSTALL.txt 2012-05-25 12:19:45.000000000 +0000 @@ -44,9 +44,9 @@ http://www.hydrogen-music.org/ The source code for the current development version can be checked out -via Subversion: +via git: - $ svn co http://svn.assembla.com/svn/hydrogen/trunk hydrogen + $ git clone git://github.com/hydrogen-music/hydrogen.git 3. Binary Packages ------------------ diff -Nru hydrogen-0.9.6~beta1/linux/debian/rules hydrogen-0.9.6~beta2/linux/debian/rules --- hydrogen-0.9.6~beta1/linux/debian/rules 2011-09-13 20:55:34.000000000 +0000 +++ hydrogen-0.9.6~beta2/linux/debian/rules 2012-05-25 12:19:45.000000000 +0000 @@ -64,8 +64,8 @@ mkdir -p $(CURDIR)/debian/hydrogen/usr/bin cd ../builddebian; $(MAKE) install - #remove not used .svn dirs - find $(CURDIR)/debian/hydrogen/ -name '.svn' | xargs rm -rf + #remove not used .git dirs + find $(CURDIR)/debian/hydrogen/ -name '.git' | xargs rm -rf docs: diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/basics/instrument.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/basics/instrument.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/basics/instrument.h 2011-12-06 11:23:10.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/basics/instrument.h 2012-05-25 12:19:45.000000000 +0000 @@ -100,9 +100,10 @@ * load an instrument from an XMLNode * \param node the XMLDode to read from * \param dk_path the directory holding the drumkit data + * \param dk_name the name of the drumkit * \return a new Instrument instance */ - static Instrument* load_from( XMLNode* node, const QString& dk_path ); + static Instrument* load_from( XMLNode* node, const QString& dk_path, const QString& dk_name ); /** * get an instrument layer from the list @@ -236,9 +237,16 @@ /** get the stop notes of the instrument */ bool is_stop_notes() const; + ///< set the name of the related drumkit + void set_drumkit_name( const QString& name ); + ///< get the name of the related drumkits + const QString& get_drumkit_name() const; + + private: int __id; ///< instrument id, should be unique QString __name; ///< instrument name + QString __drumkit_name; ///< the name of the drumkit this instrument belongs tos float __gain; ///< gain of the instrument float __volume; ///< volume of the instrument float __pan_l; ///< left pan of the instrument @@ -516,8 +524,20 @@ __layers[ idx ] = layer; } +inline void Instrument::set_drumkit_name( const QString& name ) +{ + __drumkit_name = name; +} + +inline const QString& Instrument::get_drumkit_name() const +{ + return __drumkit_name; +} + }; + + #endif // H2C_INSTRUMENT_H /* vim: set softtabstop=4 expandtab: */ diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/basics/instrument_list.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/basics/instrument_list.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/basics/instrument_list.h 2011-07-08 16:41:38.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/basics/instrument_list.h 2012-05-25 12:19:45.000000000 +0000 @@ -140,7 +140,7 @@ * \param dk_path the directory holding the drumkit data * \return a new InstrumentList instance */ - static InstrumentList* load_from( XMLNode* node, const QString& dk_path ); + static InstrumentList* load_from( XMLNode* node, const QString& dk_path, const QString& dk_name ); private: std::vector __instruments; ///< the list of instruments diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/basics/song.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/basics/song.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/basics/song.h 2011-07-08 16:41:38.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/basics/song.h 2012-05-25 12:19:45.000000000 +0000 @@ -139,6 +139,10 @@ const QString& get_license() { return __license; } + + const QString& get_author() { + return __author; + } const QString& get_filename() { return __filename; diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/config.h.in hydrogen-0.9.6~beta2/src/core/include/hydrogen/config.h.in --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/config.h.in 2011-07-01 21:09:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/config.h.in 2012-05-25 12:19:45.000000000 +0000 @@ -20,7 +20,7 @@ #define H2CORE_VERSION_PATCH @VERSION_PATCH@ #define H2CORE_VERSION "@VERSION@" #define H2CORE_REVISION "@REVISION@" -#define H2CORE_VERSION_FULL "@VERSION@-svn-@REVISION@" +#define H2CORE_VERSION_FULL "@VERSION@-@REVISION@" #cmakedefine HAVE_SSCANF #cmakedefine HAVE_RTCLOCK diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/event_queue.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/event_queue.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/event_queue.h 2011-10-21 16:00:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/event_queue.h 2012-05-25 12:19:45.000000000 +0000 @@ -24,6 +24,7 @@ #define EVENT_QUEUE_H #include +#include #include #define MAX_EVENTS 1024 @@ -46,7 +47,8 @@ EVENT_RECALCULATERUBBERBAND, EVENT_PROGRESS, EVENT_JACK_SESSION, - EVENT_PLAYLIST_LOADSONG + EVENT_PLAYLIST_LOADSONG, + EVENT_UNDO_REDO }; @@ -71,6 +73,23 @@ void push_event( EventType type, int nValue ); Event pop_event(); + struct AddMidiNoteVector + { + int m_column; //position + int m_row; //instrument row + int m_pattern; // pattern number + int m_length; + float f_velocity; + float f_pan_L; + float f_pan_R; + Note::Key nk_noteKeyVal; + Note::Octave no_octaveKeyVal; + bool b_isMidi; + bool b_isInstrumentMode; + bool b_noteExist; + }; + std::vector m_addMidiNoteVector; + private: EventQueue(); static EventQueue *__instance; diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/hydrogen.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/hydrogen.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/hydrogen.h 2011-11-04 23:07:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/hydrogen.h 2012-05-25 12:19:45.000000000 +0000 @@ -108,15 +108,15 @@ int getPatternPos(); void setPatternPos( int pos ); - + void triggerRelocateDuringPlay(); long getTickForPosition( int ); - void restartDrivers(); + void restartDrivers(); void startExportSong( const QString& filename, int rate, int depth ); - void stopExportSong(); + void stopExportSong( bool reconnectOldDriver ); AudioOutput* getAudioOutput(); MidiInput* getMidiInput(); diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/IO/JackOutput.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/IO/JackOutput.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/IO/JackOutput.h 2011-07-02 20:05:19.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/IO/JackOutput.h 2012-05-25 12:19:45.000000000 +0000 @@ -76,7 +76,6 @@ } - void setPortName( int nPort, bool bLeftChannel, const QString& sName ); void makeTrackOutputs( Song * ); void setTrackOutput( int, Instrument * ); diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/LocalFileMng.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/LocalFileMng.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/LocalFileMng.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/LocalFileMng.h 2012-05-25 12:19:45.000000000 +0000 @@ -58,7 +58,7 @@ std::vector getPatternDirList(); std::vector getSongList(); std::vector getPatternsForDrumkit( const QString& ); - std::vector getAllPatternName(); + std::vector getAllPatternNames(); int getPatternList( const QString& ); int mergeAllPatternList( std::vector ); diff -Nru hydrogen-0.9.6~beta1/src/core/include/hydrogen/Preferences.h hydrogen-0.9.6~beta2/src/core/include/hydrogen/Preferences.h --- hydrogen-0.9.6~beta1/src/core/include/hydrogen/Preferences.h 2011-11-04 23:07:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/include/hydrogen/Preferences.h 2012-05-25 12:19:45.000000000 +0000 @@ -149,7 +149,7 @@ NO_JACK_TIME_MASTER = 1, PRE_FADER = 1, SET_PLAY_OFF = 1, - BC_OFF = 1, + BC_OFF = 1 }; @@ -160,6 +160,7 @@ int m_nDefaultUILayout; + QString m_sPreferencesFilename; QString m_sPreferencesDirectory; @@ -169,20 +170,12 @@ bool __playselectedinstrument; // midi keys and keys play instrument or drumset - // __rightclickedpattereditor - // 0 = note length - // 1 = note off" - // 2 = edit velocity - // 3 = edit pan - // 4 = edit lead lag - int __rightclickedpattereditor; //right click into pattern editor add note-off-note or edit note-length - int m_nRecPreDelete; //index of record note pre delete function 0 = off int m_nRecPostDelete; bool m_bFollowPlayhead; - bool __usetimeline; + // switch to enable / disable lash, only on h2 startup bool m_brestartLash; @@ -239,8 +232,7 @@ ///Rubberband CLI QString m_rubberBandCLIexecutable; - ///rubberband bpm change queue - bool m_useTheRubberbandBpmChangeEvent; + /// Returns an instance of PreferencesMng class static void create_instance(); static Preferences* get_instance() { assert(__instance); return __instance; } @@ -586,13 +578,35 @@ jackSessionApplicationPath = path; } - bool getJackSessionUseSessionDir(){ - return m_bjackSessionUseSessionDir; +#endif + + bool getUseTimelineBpm(){ + return __useTimelineBpm; } - void setJackSessionUseSessionDir( bool val ){ - m_bjackSessionUseSessionDir = val; + void setUseTimelineBpm( bool val ){ + __useTimelineBpm = val; } -#endif + + int getRubberBandCalcTime(){ + return __rubberBandCalcTime; + } + void setRubberBandCalcTime( int val ){ + __rubberBandCalcTime = val; + } + + int getRubberBandBatchMode(){ + return m_useTheRubberbandBpmChangeEvent; + } + void setRubberBandBatchMode( int val ){ + m_useTheRubberbandBpmChangeEvent = val; + } + + int getLastOpenTab(){ + return m_nLastOpenTab; + } + void setLastOpenTab(int n){ + m_nLastOpenTab = n; + } private: static Preferences *__instance; @@ -604,6 +618,9 @@ QString demoPath; //___ General properties ___ + int __rubberBandCalcTime; + ///rubberband bpm change queue + bool m_useTheRubberbandBpmChangeEvent; bool m_bPatternModePlaysSelected; /// Behaviour of Pattern Mode bool m_brestoreLastSong; ///< Restore last song? bool m_brestoreLastPlaylist; @@ -627,12 +644,13 @@ #ifdef H2CORE_HAVE_JACKSESSION QString jackSessionUUID; QString jackSessionApplicationPath; - bool m_bjackSessionUseSessionDir; #endif bool waitingForSessionHandler; + bool __useTimelineBpm; //___ GUI properties ___ QString m_sQTStyle; + int m_nLastOpenTab; QString applicationFontFamily; int applicationFontPointSize; diff -Nru hydrogen-0.9.6~beta1/src/core/src/basics/drumkit.cpp hydrogen-0.9.6~beta2/src/core/src/basics/drumkit.cpp --- hydrogen-0.9.6~beta1/src/core/src/basics/drumkit.cpp 2011-07-22 07:34:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/basics/drumkit.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -90,21 +90,6 @@ } Drumkit* drumkit = Drumkit::load_from( &root, dk_path.left( dk_path.lastIndexOf( "/" ) ) ); if( load_samples ) drumkit->load_samples(); - /* - if( load_samples ) { - InstrumentList* instruments = drumkit->get_instruments(); - for( int i=0; isize(); i++ ) { - Instrument* instrument = ( *instruments )[i]; - for ( int n = 0; n < MAX_LAYERS; n++ ) { - InstrumentLayer* layer = instrument->get_layer( n ); - if( layer ) { - Sample* sample = layer->get_sample(); - if( sample ) sample->load(); - } - } - } - } - */ return drumkit; } @@ -126,9 +111,8 @@ WARNINGLOG( "instrumentList node not found" ); drumkit->set_instruments( new InstrumentList() ); } else { - drumkit->set_instruments( InstrumentList::load_from( &instruments_node, dk_path ) ); + drumkit->set_instruments( InstrumentList::load_from( &instruments_node, dk_path, drumkit_name ) ); } - //if( drumkit->__logger->should_log( Logger::Debug ) ) drumkit->dump(); return drumkit; } @@ -341,7 +325,7 @@ TAR* tar_file; char tar_path[1024]; strncpy( tar_path, gzd_name.toLocal8Bit(), 1024 ); - if ( tar_open( &tar_file, tar_path, NULL, O_RDONLY, 0, TAR_VERBOSE | TAR_GNU ) == -1 ) { + if ( tar_open( &tar_file, tar_path, NULL, O_RDONLY, 0, TAR_GNU ) == -1 ) { _ERRORLOG( QString( "tar_open(): %1" ).arg( QString::fromLocal8Bit( strerror( errno ) ) ) ); return false; } diff -Nru hydrogen-0.9.6~beta1/src/core/src/basics/instrument.cpp hydrogen-0.9.6~beta2/src/core/src/basics/instrument.cpp --- hydrogen-0.9.6~beta1/src/core/src/basics/instrument.cpp 2011-07-08 16:41:38.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/basics/instrument.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -155,8 +155,10 @@ } if ( is_live ) AudioEngine::get_instance()->lock( RIGHT_HERE ); + this->set_id( instrument->get_id() ); this->set_name( instrument->get_name() ); + this->set_drumkit_name( drumkit->get_name() ); this->set_gain( instrument->get_gain() ); this->set_volume( instrument->get_volume() ); this->set_pan_l( instrument->get_pan_l() ); @@ -185,11 +187,12 @@ delete drumkit; } -Instrument* Instrument::load_from( XMLNode* node, const QString& dk_path ) +Instrument* Instrument::load_from( XMLNode* node, const QString& dk_path, const QString& dk_name ) { int id = node->read_int( "id", EMPTY_INSTR_ID, false, false ); if ( id==EMPTY_INSTR_ID ) return 0; Instrument* instrument = new Instrument( id, node->read_string( "name", "" ), 0 ); + instrument->set_drumkit_name( dk_name ); instrument->set_volume( node->read_float( "volume", 1.0f ) ); instrument->set_muted( node->read_bool( "isMuted", false ) ); instrument->set_pan_l( node->read_float( "pan_L", 1.0f ) ); diff -Nru hydrogen-0.9.6~beta1/src/core/src/basics/instrument_list.cpp hydrogen-0.9.6~beta2/src/core/src/basics/instrument_list.cpp --- hydrogen-0.9.6~beta1/src/core/src/basics/instrument_list.cpp 2011-07-08 16:41:38.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/basics/instrument_list.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -63,7 +63,7 @@ } } -InstrumentList* InstrumentList::load_from( XMLNode* node, const QString& dk_path ) +InstrumentList* InstrumentList::load_from( XMLNode* node, const QString& dk_path, const QString& dk_name ) { InstrumentList* instruments = new InstrumentList(); XMLNode instrument_node = node->firstChildElement( "instrument" ); @@ -74,7 +74,7 @@ ERRORLOG( QString( "instrument count >= %2, stop reading instruments" ).arg( MAX_INSTRUMENTS ) ); break; } - Instrument* instrument = Instrument::load_from( &instrument_node, dk_path ); + Instrument* instrument = Instrument::load_from( &instrument_node, dk_path, dk_name ); if( instrument ) { ( *instruments ) << instrument; } else { diff -Nru hydrogen-0.9.6~beta1/src/core/src/basics/pattern_list.cpp hydrogen-0.9.6~beta2/src/core/src/basics/pattern_list.cpp --- hydrogen-0.9.6~beta1/src/core/src/basics/pattern_list.cpp 2011-07-18 21:30:45.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/basics/pattern_list.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -125,8 +125,6 @@ Pattern* PatternList::replace( int idx, Pattern* pattern ) { - ERRORLOG( QString("idx=%1 and __patterns.size()=%2").arg( idx ).arg( __patterns.size() ) ); - /* * if we insert a new pattern (copy, add new pattern, undo delete pattern and so on will do this) * idx is > __pattern.size(). thats why i add +1 to assert expression diff -Nru hydrogen-0.9.6~beta1/src/core/src/helpers/filesystem.cpp hydrogen-0.9.6~beta2/src/core/src/helpers/filesystem.cpp --- hydrogen-0.9.6~beta1/src/core/src/helpers/filesystem.cpp 2011-07-21 20:13:13.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/helpers/filesystem.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -59,7 +59,7 @@ #else __sys_data_path = QCoreApplication::applicationDirPath().append( "/data" ) ; #endif - __usr_data_path = QDir::homePath().append( "/Library/Application Support/Hydrogen" ); + __usr_data_path = QDir::homePath().append( "/Library/Application Support/Hydrogen/data" ); #elif WIN32 __sys_data_path = QCoreApplication::applicationDirPath().append( "/data" ) ; __usr_data_path = QCoreApplication::applicationDirPath().append( "/hydrogen/data" ) ; @@ -208,8 +208,12 @@ return false; } if ( !recursive ) { - ERRORLOG( QString( "unable to remove directory %1 without recursive parameter set to true" ).arg( path ) ); - return false; + QDir dir; + bool ret = dir.rmdir( path ); + if( !ret ) { + ERRORLOG( QString( "unable to remove dir %1 without recursive argument, maybe it is not empty?" ).arg( path ) ); + } + return ret; } return rm_fr( path ); } @@ -249,12 +253,16 @@ if( !file_readable( click_file() ) ) return false; if( !file_readable( empty_song() ) ) return false; if( !file_readable( empty_sample() ) ) return false; - if( !file_readable( sys_gui_config() ) ) return false; - if( !file_readable( sys_core_config() ) ) return false; + + //@Jeremy: Please check if those files are obsolote + //if( !file_readable( sys_gui_config() ) ) return false; + //if( !file_readable( sys_core_config() ) ) return false; + //if( !file_readable( pattern_xsd() ) ) return false; + if( !dir_readable( sys_drumkits_dir() ) ) return false; if( !file_readable( drumkit_xsd() ) ) return false; if( !file_readable( drumkit_pattern_xsd() ) ) return false; - if( !file_readable( pattern_xsd() ) ) return false; + INFOLOG( QString( "system wide data path %1 is usable." ).arg( __sys_data_path ) ); return true; } diff -Nru hydrogen-0.9.6~beta1/src/core/src/helpers/legacy.cpp hydrogen-0.9.6~beta2/src/core/src/helpers/legacy.cpp --- hydrogen-0.9.6~beta1/src/core/src/helpers/legacy.cpp 2011-07-21 20:14:05.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/helpers/legacy.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -125,7 +125,6 @@ } drumkit->set_instruments( instruments ); } - //if( drumkit->__logger->should_log( Logger::Debug ) ) drumkit->dump(); return drumkit; } diff -Nru hydrogen-0.9.6~beta1/src/core/src/helpers/xml.cpp hydrogen-0.9.6~beta2/src/core/src/helpers/xml.cpp --- hydrogen-0.9.6~beta1/src/core/src/helpers/xml.cpp 2011-07-22 07:34:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/helpers/xml.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -164,8 +164,14 @@ } QTextStream out( &file ); out << toString().toUtf8(); + out.flush(); + + bool rv = true; + if ( !toString().isEmpty() && file.size() == 0 ) + rv = false; + file.close(); - return true; + return rv; }; void XMLDoc::set_root( const QString& node_name, const QString& xmlns ) diff -Nru hydrogen-0.9.6~beta1/src/core/src/hydrogen.cpp hydrogen-0.9.6~beta2/src/core/src/hydrogen.cpp --- hydrogen-0.9.6~beta1/src/core/src/hydrogen.cpp 2011-11-08 22:10:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/hydrogen.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -119,29 +119,29 @@ AudioOutput *m_pAudioDriver = NULL; ///< Audio output QMutex mutex_OutputPointer; ///< Mutex for audio output pointer, allows multiple readers - ///< When locking this AND AudioEngine, always lock AudioEngine first. +///< When locking this AND AudioEngine, always lock AudioEngine first. MidiInput *m_pMidiDriver = NULL; ///< MIDI input MidiOutput *m_pMidiDriverOut = NULL; ///< MIDI output // overload the the > operator of Note objects for priority_queue struct compare_pNotes { -bool operator() (Note* pNote1, Note* pNote2) { - return (pNote1->get_humanize_delay() - + pNote1->get_position() * m_pAudioDriver->m_transport.m_nTickSize) - > - (pNote2->get_humanize_delay() - + pNote2->get_position() * m_pAudioDriver->m_transport.m_nTickSize); -} + bool operator() (Note* pNote1, Note* pNote2) { + return (pNote1->get_humanize_delay() + + pNote1->get_position() * m_pAudioDriver->m_transport.m_nTickSize) + > + (pNote2->get_humanize_delay() + + pNote2->get_position() * m_pAudioDriver->m_transport.m_nTickSize); + } }; - /// Song Note FIFO +/// Song Note FIFO std::priority_queue, compare_pNotes > m_songNoteQueue; std::deque m_midiNoteQueue; ///< Midi Note FIFO Song *m_pSong; ///< Current song PatternList* m_pNextPatterns; ///< Next pattern (used only in Pattern mode) bool m_bAppendNextPattern; ///< Add the next pattern to the list instead - /// of replace. +/// of replace. bool m_bDeleteNextPattern; ///< Delete the next pattern from the list. @@ -218,96 +218,96 @@ inline timeval currentTime2() { - struct timeval now; - gettimeofday( &now, NULL ); - return now; + struct timeval now; + gettimeofday( &now, NULL ); + return now; } inline int randomValue( int max ) { - return rand() % max; + return rand() % max; } inline float getGaussian( float z ) { - // gaussian distribution -- dimss - float x1, x2, w; - do { - x1 = 2.0 * ( ( ( float ) rand() ) / RAND_MAX ) - 1.0; - x2 = 2.0 * ( ( ( float ) rand() ) / RAND_MAX ) - 1.0; - w = x1 * x1 + x2 * x2; - } while ( w >= 1.0 ); + // gaussian distribution -- dimss + float x1, x2, w; + do { + x1 = 2.0 * ( ( ( float ) rand() ) / RAND_MAX ) - 1.0; + x2 = 2.0 * ( ( ( float ) rand() ) / RAND_MAX ) - 1.0; + w = x1 * x1 + x2 * x2; + } while ( w >= 1.0 ); - w = sqrtf( ( -2.0 * logf( w ) ) / w ); - return x1 * w * z + 0.0; // tunable + w = sqrtf( ( -2.0 * logf( w ) ) / w ); + return x1 * w * z + 0.0; // tunable } void audioEngine_raiseError( unsigned nErrorCode ) { - EventQueue::get_instance()->push_event( EVENT_ERROR, nErrorCode ); + EventQueue::get_instance()->push_event( EVENT_ERROR, nErrorCode ); } void updateTickSize() { - float sampleRate = ( float )m_pAudioDriver->getSampleRate(); - m_pAudioDriver->m_transport.m_nTickSize = - ( sampleRate * 60.0 / m_pSong->__bpm / m_pSong->__resolution ); + float sampleRate = ( float )m_pAudioDriver->getSampleRate(); + m_pAudioDriver->m_transport.m_nTickSize = + ( sampleRate * 60.0 / m_pSong->__bpm / m_pSong->__resolution ); } void audioEngine_init() { - ___INFOLOG( "*** Hydrogen audio engine init ***" ); + ___INFOLOG( "*** Hydrogen audio engine init ***" ); - // check current state - if ( m_audioEngineState != STATE_UNINITIALIZED ) { - ___ERRORLOG( "Error the audio engine is not in UNINITIALIZED state" ); - AudioEngine::get_instance()->unlock(); - return; - } - - m_pSong = NULL; - m_pPlayingPatterns = new PatternList(); - m_pNextPatterns = new PatternList(); - m_nSongPos = -1; - m_nSelectedPatternNumber = 0; - m_nSelectedInstrumentNumber = 0; - m_nPatternTickPosition = 0; - m_pMetronomeInstrument = NULL; - m_pAudioDriver = NULL; - - m_pMainBuffer_L = NULL; - m_pMainBuffer_R = NULL; - - srand( time( NULL ) ); - - // Create metronome instrument - QString sMetronomeFilename = Filesystem::click_file(); - m_pMetronomeInstrument = - new Instrument( METRONOME_INSTR_ID, "metronome" ); - m_pMetronomeInstrument->set_layer( - new InstrumentLayer( Sample::load( sMetronomeFilename ) ), - 0 - ); + // check current state + if ( m_audioEngineState != STATE_UNINITIALIZED ) { + ___ERRORLOG( "Error the audio engine is not in UNINITIALIZED state" ); + AudioEngine::get_instance()->unlock(); + return; + } + + m_pSong = NULL; + m_pPlayingPatterns = new PatternList(); + m_pNextPatterns = new PatternList(); + m_nSongPos = -1; + m_nSelectedPatternNumber = 0; + m_nSelectedInstrumentNumber = 0; + m_nPatternTickPosition = 0; + m_pMetronomeInstrument = NULL; + m_pAudioDriver = NULL; + + m_pMainBuffer_L = NULL; + m_pMainBuffer_R = NULL; + + srand( time( NULL ) ); + + // Create metronome instrument + QString sMetronomeFilename = Filesystem::click_file(); + m_pMetronomeInstrument = + new Instrument( METRONOME_INSTR_ID, "metronome" ); + m_pMetronomeInstrument->set_layer( + new InstrumentLayer( Sample::load( sMetronomeFilename ) ), + 0 + ); - // Change the current audio engine state - m_audioEngineState = STATE_INITIALIZED; + // Change the current audio engine state + m_audioEngineState = STATE_INITIALIZED; #ifdef H2CORE_HAVE_LADSPA - Effects::create_instance(); + Effects::create_instance(); #endif - AudioEngine::create_instance(); - Playlist::create_instance(); + AudioEngine::create_instance(); + Playlist::create_instance(); - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_INITIALIZED ); + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_INITIALIZED ); } @@ -315,45 +315,45 @@ void audioEngine_destroy() { - // check current state - if ( m_audioEngineState != STATE_INITIALIZED ) { - ___ERRORLOG( "Error the audio engine is not in INITIALIZED state" ); - return; - } - AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - ___INFOLOG( "*** Hydrogen audio engine shutdown ***" ); - - // delete all copied notes in the song notes queue - while ( !m_songNoteQueue.empty() ) { - m_songNoteQueue.top()->get_instrument()->dequeue(); - delete m_songNoteQueue.top(); - m_songNoteQueue.pop(); - } - // delete all copied notes in the midi notes queue - for ( unsigned i = 0; i < m_midiNoteQueue.size(); ++i ) { - Note *note = m_midiNoteQueue[i]; - delete note; - note = NULL; - } - m_midiNoteQueue.clear(); - - // change the current audio engine state - m_audioEngineState = STATE_UNINITIALIZED; - - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_UNINITIALIZED ); - - delete m_pPlayingPatterns; - m_pPlayingPatterns = NULL; + // check current state + if ( m_audioEngineState != STATE_INITIALIZED ) { + ___ERRORLOG( "Error the audio engine is not in INITIALIZED state" ); + return; + } + AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + ___INFOLOG( "*** Hydrogen audio engine shutdown ***" ); + + // delete all copied notes in the song notes queue + while ( !m_songNoteQueue.empty() ) { + m_songNoteQueue.top()->get_instrument()->dequeue(); + delete m_songNoteQueue.top(); + m_songNoteQueue.pop(); + } + // delete all copied notes in the midi notes queue + for ( unsigned i = 0; i < m_midiNoteQueue.size(); ++i ) { + Note *note = m_midiNoteQueue[i]; + delete note; + note = NULL; + } + m_midiNoteQueue.clear(); + + // change the current audio engine state + m_audioEngineState = STATE_UNINITIALIZED; + + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_UNINITIALIZED ); + + delete m_pPlayingPatterns; + m_pPlayingPatterns = NULL; - delete m_pNextPatterns; - m_pNextPatterns = NULL; + delete m_pNextPatterns; + m_pNextPatterns = NULL; - delete m_pMetronomeInstrument; - m_pMetronomeInstrument = NULL; + delete m_pMetronomeInstrument; + m_pMetronomeInstrument = NULL; - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); } @@ -366,39 +366,39 @@ /// return -2 = Driver connect() error int audioEngine_start( bool bLockEngine, unsigned nTotalFrames ) { - if ( bLockEngine ) { - AudioEngine::get_instance()->lock( RIGHT_HERE ); - } - - ___INFOLOG( "[audioEngine_start]" ); - - // check current state - if ( m_audioEngineState != STATE_READY ) { - ___ERRORLOG( "Error the audio engine is not in READY state" ); - if ( bLockEngine ) { - AudioEngine::get_instance()->unlock(); - } - return 0; // FIXME!! - } - - m_fMasterPeak_L = 0.0f; - m_fMasterPeak_R = 0.0f; - m_pAudioDriver->m_transport.m_nFrames = nTotalFrames; // reset total frames - m_nSongPos = -1; - m_nPatternStartTick = -1; - m_nPatternTickPosition = 0; - - // prepare the tickSize for this song - updateTickSize(); - - // change the current audio engine state - m_audioEngineState = STATE_PLAYING; - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_PLAYING ); - - if ( bLockEngine ) { - AudioEngine::get_instance()->unlock(); - } - return 0; // per ora restituisco sempre OK + if ( bLockEngine ) { + AudioEngine::get_instance()->lock( RIGHT_HERE ); + } + + ___INFOLOG( "[audioEngine_start]" ); + + // check current state + if ( m_audioEngineState != STATE_READY ) { + ___ERRORLOG( "Error the audio engine is not in READY state" ); + if ( bLockEngine ) { + AudioEngine::get_instance()->unlock(); + } + return 0; // FIXME!! + } + + m_fMasterPeak_L = 0.0f; + m_fMasterPeak_R = 0.0f; + m_pAudioDriver->m_transport.m_nFrames = nTotalFrames; // reset total frames + m_nSongPos = -1; + m_nPatternStartTick = -1; + m_nPatternTickPosition = 0; + + // prepare the tickSize for this song + updateTickSize(); + + // change the current audio engine state + m_audioEngineState = STATE_PLAYING; + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_PLAYING ); + + if ( bLockEngine ) { + AudioEngine::get_instance()->unlock(); + } + return 0; // per ora restituisco sempre OK } @@ -406,53 +406,53 @@ /// Stop the audio engine void audioEngine_stop( bool bLockEngine ) { - if ( bLockEngine ) { - AudioEngine::get_instance()->lock( RIGHT_HERE ); - } - ___INFOLOG( "[audioEngine_stop]" ); - - // check current state - if ( m_audioEngineState != STATE_PLAYING ) { - ___ERRORLOG( "Error the audio engine is not in PLAYING state" ); - if ( bLockEngine ) { - AudioEngine::get_instance()->unlock(); - } - return; - } - - // change the current audio engine state - m_audioEngineState = STATE_READY; - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_READY ); - - m_fMasterPeak_L = 0.0f; - m_fMasterPeak_R = 0.0f; -// m_nPatternTickPosition = 0; - m_nPatternStartTick = -1; - - // delete all copied notes in the song notes queue - while(!m_songNoteQueue.empty()){ - m_songNoteQueue.top()->get_instrument()->dequeue(); - delete m_songNoteQueue.top(); - m_songNoteQueue.pop(); - } - /* // delete all copied notes in the playing notes queue - for (unsigned i = 0; i < m_playingNotesQueue.size(); ++i) { - Note *note = m_playingNotesQueue[i]; - delete note; - } - m_playingNotesQueue.clear(); - */ - - // delete all copied notes in the midi notes queue - for ( unsigned i = 0; i < m_midiNoteQueue.size(); ++i ) { - Note *note = m_midiNoteQueue[i]; - delete note; - } - m_midiNoteQueue.clear(); - - if ( bLockEngine ) { - AudioEngine::get_instance()->unlock(); - } + if ( bLockEngine ) { + AudioEngine::get_instance()->lock( RIGHT_HERE ); + } + ___INFOLOG( "[audioEngine_stop]" ); + + // check current state + if ( m_audioEngineState != STATE_PLAYING ) { + ___ERRORLOG( "Error the audio engine is not in PLAYING state" ); + if ( bLockEngine ) { + AudioEngine::get_instance()->unlock(); + } + return; + } + + // change the current audio engine state + m_audioEngineState = STATE_READY; + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_READY ); + + m_fMasterPeak_L = 0.0f; + m_fMasterPeak_R = 0.0f; + // m_nPatternTickPosition = 0; + m_nPatternStartTick = -1; + + // delete all copied notes in the song notes queue + while(!m_songNoteQueue.empty()){ + m_songNoteQueue.top()->get_instrument()->dequeue(); + delete m_songNoteQueue.top(); + m_songNoteQueue.pop(); + } + /* // delete all copied notes in the playing notes queue + for (unsigned i = 0; i < m_playingNotesQueue.size(); ++i) { + Note *note = m_playingNotesQueue[i]; + delete note; + } + m_playingNotesQueue.clear(); + */ + + // delete all copied notes in the midi notes queue + for ( unsigned i = 0; i < m_midiNoteQueue.size(); ++i ) { + Note *note = m_midiNoteQueue[i]; + delete note; + } + m_midiNoteQueue.clear(); + + if ( bLockEngine ) { + AudioEngine::get_instance()->unlock(); + } } // @@ -461,233 +461,233 @@ inline void audioEngine_process_checkBPMChanged() { - if ( ( m_audioEngineState == STATE_READY ) || ( m_audioEngineState == STATE_PLAYING ) ) { + if ( ( m_audioEngineState == STATE_READY ) || ( m_audioEngineState == STATE_PLAYING ) ) { + + float fNewTickSize = + m_pAudioDriver->getSampleRate() * 60.0 + / m_pSong->__bpm + / m_pSong->__resolution; + + if ( fNewTickSize != m_pAudioDriver->m_transport.m_nTickSize ) { + // cerco di convertire ... + float fTickNumber = + ( float )m_pAudioDriver->m_transport.m_nFrames + / ( float )m_pAudioDriver->m_transport.m_nTickSize; + + m_pAudioDriver->m_transport.m_nTickSize = fNewTickSize; + + if ( m_pAudioDriver->m_transport.m_nTickSize == 0 ) { + return; + } + + ___WARNINGLOG( "Tempo change: Recomputing ticksize and frame position" ); + long long nNewFrames = ( long long )( fTickNumber * fNewTickSize ); + // update frame position + m_pAudioDriver->m_transport.m_nFrames = nNewFrames; - float fNewTickSize = - m_pAudioDriver->getSampleRate() * 60.0 - / m_pSong->__bpm - / m_pSong->__resolution; - - if ( fNewTickSize != m_pAudioDriver->m_transport.m_nTickSize ) { - // cerco di convertire ... - float fTickNumber = - ( float )m_pAudioDriver->m_transport.m_nFrames - / ( float )m_pAudioDriver->m_transport.m_nTickSize; - - m_pAudioDriver->m_transport.m_nTickSize = fNewTickSize; - - if ( m_pAudioDriver->m_transport.m_nTickSize == 0 ) { - return; - } - - ___WARNINGLOG( "Tempo change: Recomputing ticksize and frame position" ); - long long nNewFrames = ( long long )( fTickNumber * fNewTickSize ); - // update frame position - m_pAudioDriver->m_transport.m_nFrames = nNewFrames; - #ifdef H2CORE_HAVE_JACK - if ( JackOutput::class_name() == m_pAudioDriver->class_name() - && m_audioEngineState == STATE_PLAYING ) { - static_cast< JackOutput* >( m_pAudioDriver ) - ->calculateFrameOffset(); - } -#endif - EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); - } - } + if ( JackOutput::class_name() == m_pAudioDriver->class_name() + && m_audioEngineState == STATE_PLAYING ) { + static_cast< JackOutput* >( m_pAudioDriver ) + ->calculateFrameOffset(); + } +#endif + EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); + } + } } inline void audioEngine_process_playNotes( unsigned long nframes ) { - unsigned int framepos; + unsigned int framepos; - if ( m_audioEngineState == STATE_PLAYING ) { - framepos = m_pAudioDriver->m_transport.m_nFrames; - } else { - // use this to support realtime events when not playing - framepos = m_nRealtimeFrames; - } - - // reading from m_songNoteQueue - while ( !m_songNoteQueue.empty() ) { - Note *pNote = m_songNoteQueue.top(); - - // verifico se la nota rientra in questo ciclo - unsigned int noteStartInFrames = - (int)( pNote->get_position() * m_pAudioDriver->m_transport.m_nTickSize ); - - // if there is a negative Humanize delay, take into account so - // we don't miss the time slice. ignore positive delay, or we - // might end the queue processing prematurely based on NoteQueue - // placement. the sampler handles positive delay. - if (pNote->get_humanize_delay() < 0) { - noteStartInFrames += pNote->get_humanize_delay(); - } - - // m_nTotalFrames <= NotePos < m_nTotalFrames + bufferSize - bool isNoteStart = ( ( noteStartInFrames >= framepos ) - && ( noteStartInFrames < ( framepos + nframes ) ) ); - bool isOldNote = noteStartInFrames < framepos; - if ( isNoteStart || isOldNote ) { - // Humanize - Velocity parameter - if ( m_pSong->get_humanize_velocity_value() != 0 ) { - float random = m_pSong->get_humanize_velocity_value() - * getGaussian( 0.2 ); - pNote->set_velocity( - pNote->get_velocity() - + ( random - - ( m_pSong->get_humanize_velocity_value() / 2.0 ) ) - ); - if ( pNote->get_velocity() > 1.0 ) { - pNote->set_velocity( 1.0 ); - } else if ( pNote->get_velocity() < 0.0 ) { - pNote->set_velocity( 0.0 ); - } - } - - // Random Pitch ;) - const float fMaxPitchDeviation = 2.0; - pNote->set_pitch( pNote->get_pitch() - + ( fMaxPitchDeviation * getGaussian( 0.2 ) - - fMaxPitchDeviation / 2.0 ) - * pNote->get_instrument()->get_random_pitch_factor() ); - - Instrument * noteInstrument = pNote->get_instrument(); - if ( noteInstrument->is_stop_notes() ){ - Note *pOffNote = new Note( noteInstrument, - 0.0, - 0.0, - 0.0, - 0.0, - -1, - 0 ); - pOffNote->set_note_off( true ); - AudioEngine::get_instance()->get_sampler()->note_on( pOffNote ); - } - - AudioEngine::get_instance()->get_sampler()->note_on( pNote ); - - m_songNoteQueue.pop(); // rimuovo la nota dalla lista di note - pNote->get_instrument()->dequeue(); - // raise noteOn event - int nInstrument = m_pSong->get_instrument_list()->index( pNote->get_instrument() ); - EventQueue::get_instance()->push_event( EVENT_NOTEON, nInstrument ); - continue; - } else { - // this note will not be played - break; - } - } + if ( m_audioEngineState == STATE_PLAYING ) { + framepos = m_pAudioDriver->m_transport.m_nFrames; + } else { + // use this to support realtime events when not playing + framepos = m_nRealtimeFrames; + } + + // reading from m_songNoteQueue + while ( !m_songNoteQueue.empty() ) { + Note *pNote = m_songNoteQueue.top(); + + // verifico se la nota rientra in questo ciclo + unsigned int noteStartInFrames = + (int)( pNote->get_position() * m_pAudioDriver->m_transport.m_nTickSize ); + + // if there is a negative Humanize delay, take into account so + // we don't miss the time slice. ignore positive delay, or we + // might end the queue processing prematurely based on NoteQueue + // placement. the sampler handles positive delay. + if (pNote->get_humanize_delay() < 0) { + noteStartInFrames += pNote->get_humanize_delay(); + } + + // m_nTotalFrames <= NotePos < m_nTotalFrames + bufferSize + bool isNoteStart = ( ( noteStartInFrames >= framepos ) + && ( noteStartInFrames < ( framepos + nframes ) ) ); + bool isOldNote = noteStartInFrames < framepos; + if ( isNoteStart || isOldNote ) { + // Humanize - Velocity parameter + if ( m_pSong->get_humanize_velocity_value() != 0 ) { + float random = m_pSong->get_humanize_velocity_value() + * getGaussian( 0.2 ); + pNote->set_velocity( + pNote->get_velocity() + + ( random + - ( m_pSong->get_humanize_velocity_value() / 2.0 ) ) + ); + if ( pNote->get_velocity() > 1.0 ) { + pNote->set_velocity( 1.0 ); + } else if ( pNote->get_velocity() < 0.0 ) { + pNote->set_velocity( 0.0 ); + } + } + + // Random Pitch ;) + const float fMaxPitchDeviation = 2.0; + pNote->set_pitch( pNote->get_pitch() + + ( fMaxPitchDeviation * getGaussian( 0.2 ) + - fMaxPitchDeviation / 2.0 ) + * pNote->get_instrument()->get_random_pitch_factor() ); + + Instrument * noteInstrument = pNote->get_instrument(); + if ( noteInstrument->is_stop_notes() ){ + Note *pOffNote = new Note( noteInstrument, + 0.0, + 0.0, + 0.0, + 0.0, + -1, + 0 ); + pOffNote->set_note_off( true ); + AudioEngine::get_instance()->get_sampler()->note_on( pOffNote ); + } + + AudioEngine::get_instance()->get_sampler()->note_on( pNote ); + + m_songNoteQueue.pop(); // rimuovo la nota dalla lista di note + pNote->get_instrument()->dequeue(); + // raise noteOn event + int nInstrument = m_pSong->get_instrument_list()->index( pNote->get_instrument() ); + EventQueue::get_instance()->push_event( EVENT_NOTEON, nInstrument ); + continue; + } else { + // this note will not be played + break; + } + } } void audioEngine_seek( long long nFrames, bool bLoopMode ) { - if ( m_pAudioDriver->m_transport.m_nFrames == nFrames ) { - return; - } - - if ( nFrames < 0 ) { - ___ERRORLOG( "nFrames < 0" ); - } - - char tmp[200]; - sprintf( tmp, "seek in %lld (old pos = %d)", - nFrames, - ( int )m_pAudioDriver->m_transport.m_nFrames ); - ___INFOLOG( tmp ); - - m_pAudioDriver->m_transport.m_nFrames = nFrames; - - int tickNumber_start = ( unsigned )( - m_pAudioDriver->m_transport.m_nFrames - / m_pAudioDriver->m_transport.m_nTickSize ); -// sprintf(tmp, "[audioEngine_seek()] tickNumber_start = %d", tickNumber_start); -// hydrogenInstance->infoLog(tmp); - - bool loop = m_pSong->is_loop_enabled(); - - if ( bLoopMode ) { - loop = true; - } - - m_nSongPos = findPatternInTick( tickNumber_start, loop, &m_nPatternStartTick ); -// sprintf(tmp, "[audioEngine_seek()] m_nSongPos = %d", m_nSongPos); -// hydrogenInstance->infoLog(tmp); + if ( m_pAudioDriver->m_transport.m_nFrames == nFrames ) { + return; + } + + if ( nFrames < 0 ) { + ___ERRORLOG( "nFrames < 0" ); + } + + char tmp[200]; + sprintf( tmp, "seek in %lld (old pos = %d)", + nFrames, + ( int )m_pAudioDriver->m_transport.m_nFrames ); + ___INFOLOG( tmp ); + + m_pAudioDriver->m_transport.m_nFrames = nFrames; + + int tickNumber_start = ( unsigned )( + m_pAudioDriver->m_transport.m_nFrames + / m_pAudioDriver->m_transport.m_nTickSize ); + // sprintf(tmp, "[audioEngine_seek()] tickNumber_start = %d", tickNumber_start); + // hydrogenInstance->infoLog(tmp); + + bool loop = m_pSong->is_loop_enabled(); + + if ( bLoopMode ) { + loop = true; + } + + m_nSongPos = findPatternInTick( tickNumber_start, loop, &m_nPatternStartTick ); + // sprintf(tmp, "[audioEngine_seek()] m_nSongPos = %d", m_nSongPos); + // hydrogenInstance->infoLog(tmp); - audioEngine_clearNoteQueue(); + audioEngine_clearNoteQueue(); } inline void audioEngine_process_transport() { - if ( ( m_audioEngineState == STATE_READY ) - || ( m_audioEngineState == STATE_PLAYING ) ) { - m_pAudioDriver->updateTransportInfo(); - unsigned long nNewFrames = m_pAudioDriver->m_transport.m_nFrames; - - // ??? audioEngine_seek returns IMMEDIATELY - // when nNewFrames == m_pAudioDriver->m_transport.m_nFrames ??? - // audioEngine_seek( nNewFrames, true ); - - switch ( m_pAudioDriver->m_transport.m_status ) { - case TransportInfo::ROLLING: - - if ( m_audioEngineState == STATE_READY ) { - audioEngine_start( false, nNewFrames ); // no engine lock - } - - if ( m_pSong->__bpm != m_pAudioDriver->m_transport.m_nBPM ) { - ___INFOLOG( - QString( "song bpm: (%1) gets transport bpm: (%2)" ) - .arg( m_pSong->__bpm ) - .arg( m_pAudioDriver->m_transport.m_nBPM ) ); - - m_pSong->__bpm = m_pAudioDriver->m_transport.m_nBPM; - } - - m_nRealtimeFrames = m_pAudioDriver->m_transport.m_nFrames; - break; - - - case TransportInfo::STOPPED: - if ( m_audioEngineState == STATE_PLAYING ) { - audioEngine_stop( false ); // no engine lock - } - - if ( m_pSong->__bpm != m_pAudioDriver->m_transport.m_nBPM ) { - m_pSong->__bpm = m_pAudioDriver->m_transport.m_nBPM; - } - - // go ahead and increment the realtimeframes by buffersize - // to support our realtime keyboard and midi event timing - m_nRealtimeFrames += m_nBufferSize; - break; - } - } + if ( ( m_audioEngineState == STATE_READY ) + || ( m_audioEngineState == STATE_PLAYING ) ) { + m_pAudioDriver->updateTransportInfo(); + unsigned long nNewFrames = m_pAudioDriver->m_transport.m_nFrames; + + // ??? audioEngine_seek returns IMMEDIATELY + // when nNewFrames == m_pAudioDriver->m_transport.m_nFrames ??? + // audioEngine_seek( nNewFrames, true ); + + switch ( m_pAudioDriver->m_transport.m_status ) { + case TransportInfo::ROLLING: + + if ( m_audioEngineState == STATE_READY ) { + audioEngine_start( false, nNewFrames ); // no engine lock + } + + if ( m_pSong->__bpm != m_pAudioDriver->m_transport.m_nBPM ) { + ___INFOLOG( + QString( "song bpm: (%1) gets transport bpm: (%2)" ) + .arg( m_pSong->__bpm ) + .arg( m_pAudioDriver->m_transport.m_nBPM ) ); + + m_pSong->__bpm = m_pAudioDriver->m_transport.m_nBPM; + } + + m_nRealtimeFrames = m_pAudioDriver->m_transport.m_nFrames; + break; + + + case TransportInfo::STOPPED: + if ( m_audioEngineState == STATE_PLAYING ) { + audioEngine_stop( false ); // no engine lock + } + + if ( m_pSong->__bpm != m_pAudioDriver->m_transport.m_nBPM ) { + m_pSong->__bpm = m_pAudioDriver->m_transport.m_nBPM; + } + + // go ahead and increment the realtimeframes by buffersize + // to support our realtime keyboard and midi event timing + m_nRealtimeFrames += m_nBufferSize; + break; + } + } } void audioEngine_clearNoteQueue() { - //___INFOLOG( "clear notes..."); + //___INFOLOG( "clear notes..."); - // delete all copied notes in the song notes queue - while (!m_songNoteQueue.empty()) { - m_songNoteQueue.top()->get_instrument()->dequeue(); - delete m_songNoteQueue.top(); - m_songNoteQueue.pop(); - } - - AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); - - // delete all copied notes in the midi notes queue - for ( unsigned i = 0; i < m_midiNoteQueue.size(); ++i ) { - delete m_midiNoteQueue[i]; - } - m_midiNoteQueue.clear(); + // delete all copied notes in the song notes queue + while (!m_songNoteQueue.empty()) { + m_songNoteQueue.top()->get_instrument()->dequeue(); + delete m_songNoteQueue.top(); + m_songNoteQueue.pop(); + } + + AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); + + // delete all copied notes in the midi notes queue + for ( unsigned i = 0; i < m_midiNoteQueue.size(); ++i ) { + delete m_midiNoteQueue[i]; + } + m_midiNoteQueue.clear(); } @@ -696,230 +696,230 @@ /// Clear all audio buffers inline void audioEngine_process_clearAudioBuffers( uint32_t nFrames ) { - QMutexLocker mx( &mutex_OutputPointer ); + QMutexLocker mx( &mutex_OutputPointer ); - // clear main out Left and Right - if ( m_pAudioDriver ) { - m_pMainBuffer_L = m_pAudioDriver->getOut_L(); - m_pMainBuffer_R = m_pAudioDriver->getOut_R(); - } else { - m_pMainBuffer_L = m_pMainBuffer_R = 0; - } - if ( m_pMainBuffer_L ) { - memset( m_pMainBuffer_L, 0, nFrames * sizeof( float ) ); - } - if ( m_pMainBuffer_R ) { - memset( m_pMainBuffer_R, 0, nFrames * sizeof( float ) ); - } + // clear main out Left and Right + if ( m_pAudioDriver ) { + m_pMainBuffer_L = m_pAudioDriver->getOut_L(); + m_pMainBuffer_R = m_pAudioDriver->getOut_R(); + } else { + m_pMainBuffer_L = m_pMainBuffer_R = 0; + } + if ( m_pMainBuffer_L ) { + memset( m_pMainBuffer_L, 0, nFrames * sizeof( float ) ); + } + if ( m_pMainBuffer_R ) { + memset( m_pMainBuffer_R, 0, nFrames * sizeof( float ) ); + } #ifdef H2CORE_HAVE_JACK - JackOutput* jo = dynamic_cast(m_pAudioDriver); - if( jo && jo->has_track_outs() ) { - float* buf; - int k; - for( k=0 ; kgetNumTracks() ; ++k ) { - buf = jo->getTrackOut_L(k); - if( buf ) { - memset( buf, 0, nFrames * sizeof( float ) ); - } - buf = jo->getTrackOut_R(k); - if( buf ) { - memset( buf, 0, nFrames * sizeof( float ) ); - } - } - } + JackOutput* jo = dynamic_cast(m_pAudioDriver); + if( jo && jo->has_track_outs() ) { + float* buf; + int k; + for( k=0 ; kgetNumTracks() ; ++k ) { + buf = jo->getTrackOut_L(k); + if( buf ) { + memset( buf, 0, nFrames * sizeof( float ) ); + } + buf = jo->getTrackOut_R(k); + if( buf ) { + memset( buf, 0, nFrames * sizeof( float ) ); + } + } + } #endif - mx.unlock(); + mx.unlock(); #ifdef H2CORE_HAVE_LADSPA - if ( m_audioEngineState >= STATE_READY ) { - Effects* pEffects = Effects::get_instance(); - for ( unsigned i = 0; i < MAX_FX; ++i ) { // clear FX buffers - LadspaFX* pFX = pEffects->getLadspaFX( i ); - if ( pFX ) { - assert( pFX->m_pBuffer_L ); - assert( pFX->m_pBuffer_R ); - memset( pFX->m_pBuffer_L, 0, nFrames * sizeof( float ) ); - memset( pFX->m_pBuffer_R, 0, nFrames * sizeof( float ) ); - } - } - } + if ( m_audioEngineState >= STATE_READY ) { + Effects* pEffects = Effects::get_instance(); + for ( unsigned i = 0; i < MAX_FX; ++i ) { // clear FX buffers + LadspaFX* pFX = pEffects->getLadspaFX( i ); + if ( pFX ) { + assert( pFX->m_pBuffer_L ); + assert( pFX->m_pBuffer_R ); + memset( pFX->m_pBuffer_L, 0, nFrames * sizeof( float ) ); + memset( pFX->m_pBuffer_R, 0, nFrames * sizeof( float ) ); + } + } + } #endif } /// Main audio processing function. Called by audio drivers. int audioEngine_process( uint32_t nframes, void* /*arg*/ ) { - timeval startTimeval = currentTime2(); + timeval startTimeval = currentTime2(); - audioEngine_process_clearAudioBuffers( nframes ); + audioEngine_process_clearAudioBuffers( nframes ); - if( m_audioEngineState < STATE_READY) { - return 0; - } - - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - if( m_audioEngineState < STATE_READY) { - AudioEngine::get_instance()->unlock(); - return 0; - } - - if ( m_nBufferSize != nframes ) { - ___INFOLOG( - QString( "Buffer size changed. Old size = %1, new size = %2" ) - .arg( m_nBufferSize ) - .arg( nframes ) - ); - m_nBufferSize = nframes; - } - - // m_pAudioDriver->bpm updates Song->__bpm. (!!(Calls audioEngine_seek)) - audioEngine_process_transport(); - audioEngine_process_checkBPMChanged(); // m_pSong->__bpm decides tick size - - bool sendPatternChange = false; - // always update note queue.. could come from pattern or realtime input - // (midi, keyboard) - int res2 = audioEngine_updateNoteQueue( nframes ); - if ( res2 == -1 ) { // end of song - ___INFOLOG( "End of song received, calling engine_stop()" ); - AudioEngine::get_instance()->unlock(); - m_pAudioDriver->stop(); - m_pAudioDriver->locate( 0 ); // locate 0, reposition from start of the song - - if ( ( m_pAudioDriver->class_name() == DiskWriterDriver::class_name() ) - || ( m_pAudioDriver->class_name() == FakeDriver::class_name() ) ) { - ___INFOLOG( "End of song." ); - return 1; // kill the audio AudioDriver thread - } + if( m_audioEngineState < STATE_READY) { + return 0; + } + + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + if( m_audioEngineState < STATE_READY) { + AudioEngine::get_instance()->unlock(); + return 0; + } + + if ( m_nBufferSize != nframes ) { + ___INFOLOG( + QString( "Buffer size changed. Old size = %1, new size = %2" ) + .arg( m_nBufferSize ) + .arg( nframes ) + ); + m_nBufferSize = nframes; + } + + // m_pAudioDriver->bpm updates Song->__bpm. (!!(Calls audioEngine_seek)) + audioEngine_process_transport(); + audioEngine_process_checkBPMChanged(); // m_pSong->__bpm decides tick size + + bool sendPatternChange = false; + // always update note queue.. could come from pattern or realtime input + // (midi, keyboard) + int res2 = audioEngine_updateNoteQueue( nframes ); + if ( res2 == -1 ) { // end of song + ___INFOLOG( "End of song received, calling engine_stop()" ); + AudioEngine::get_instance()->unlock(); + m_pAudioDriver->stop(); + m_pAudioDriver->locate( 0 ); // locate 0, reposition from start of the song + + if ( ( m_pAudioDriver->class_name() == DiskWriterDriver::class_name() ) + || ( m_pAudioDriver->class_name() == FakeDriver::class_name() ) ) { + ___INFOLOG( "End of song." ); + return 1; // kill the audio AudioDriver thread + } #ifdef H2CORE_HAVE_JACK - else if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { - // Do something clever :-s ... Jakob Lund - // Mainly to keep sync with Ardour. - static_cast(m_pAudioDriver)->locateInNCycles( 0 ); - } -#endif - return 0; - } else if ( res2 == 2 ) { // send pattern change - sendPatternChange = true; - } - - // play all notes - audioEngine_process_playNotes( nframes ); - - // SAMPLER - AudioEngine::get_instance()->get_sampler()->process( nframes, m_pSong ); - float* out_L = AudioEngine::get_instance()->get_sampler()->__main_out_L; - float* out_R = AudioEngine::get_instance()->get_sampler()->__main_out_R; - for ( unsigned i = 0; i < nframes; ++i ) { - m_pMainBuffer_L[ i ] += out_L[ i ]; - m_pMainBuffer_R[ i ] += out_R[ i ]; - } - - // SYNTH - AudioEngine::get_instance()->get_synth()->process( nframes ); - out_L = AudioEngine::get_instance()->get_synth()->m_pOut_L; - out_R = AudioEngine::get_instance()->get_synth()->m_pOut_R; - for ( unsigned i = 0; i < nframes; ++i ) { - m_pMainBuffer_L[ i ] += out_L[ i ]; - m_pMainBuffer_R[ i ] += out_R[ i ]; - } + else if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { + // Do something clever :-s ... Jakob Lund + // Mainly to keep sync with Ardour. + static_cast(m_pAudioDriver)->locateInNCycles( 0 ); + } +#endif + return 0; + } else if ( res2 == 2 ) { // send pattern change + sendPatternChange = true; + } + + // play all notes + audioEngine_process_playNotes( nframes ); + + // SAMPLER + AudioEngine::get_instance()->get_sampler()->process( nframes, m_pSong ); + float* out_L = AudioEngine::get_instance()->get_sampler()->__main_out_L; + float* out_R = AudioEngine::get_instance()->get_sampler()->__main_out_R; + for ( unsigned i = 0; i < nframes; ++i ) { + m_pMainBuffer_L[ i ] += out_L[ i ]; + m_pMainBuffer_R[ i ] += out_R[ i ]; + } + + // SYNTH + AudioEngine::get_instance()->get_synth()->process( nframes ); + out_L = AudioEngine::get_instance()->get_synth()->m_pOut_L; + out_R = AudioEngine::get_instance()->get_synth()->m_pOut_R; + for ( unsigned i = 0; i < nframes; ++i ) { + m_pMainBuffer_L[ i ] += out_L[ i ]; + m_pMainBuffer_R[ i ] += out_R[ i ]; + } - timeval renderTime_end = currentTime2(); + timeval renderTime_end = currentTime2(); - timeval ladspaTime_start = renderTime_end; + timeval ladspaTime_start = renderTime_end; #ifdef H2CORE_HAVE_LADSPA - // Process LADSPA FX - if ( m_audioEngineState >= STATE_READY ) { - for ( unsigned nFX = 0; nFX < MAX_FX; ++nFX ) { - LadspaFX *pFX = Effects::get_instance()->getLadspaFX( nFX ); - if ( ( pFX ) && ( pFX->isEnabled() ) ) { - pFX->processFX( nframes ); - float *buf_L = NULL; - float *buf_R = NULL; - if ( pFX->getPluginType() == LadspaFX::STEREO_FX ) { - buf_L = pFX->m_pBuffer_L; - buf_R = pFX->m_pBuffer_R; - } else { // MONO FX - buf_L = pFX->m_pBuffer_L; - buf_R = buf_L; - } - for ( unsigned i = 0; i < nframes; ++i ) { - m_pMainBuffer_L[ i ] += buf_L[ i ]; - m_pMainBuffer_R[ i ] += buf_R[ i ]; - if ( buf_L[ i ] > m_fFXPeak_L[nFX] ) - m_fFXPeak_L[nFX] = buf_L[ i ]; - if ( buf_R[ i ] > m_fFXPeak_R[nFX] ) - m_fFXPeak_R[nFX] = buf_R[ i ]; - } - } - } - } -#endif - timeval ladspaTime_end = currentTime2(); - - // update master peaks - float val_L; - float val_R; - if ( m_audioEngineState >= STATE_READY ) { - for ( unsigned i = 0; i < nframes; ++i ) { - val_L = m_pMainBuffer_L[i]; - val_R = m_pMainBuffer_R[i]; - if ( val_L > m_fMasterPeak_L ) { - m_fMasterPeak_L = val_L; - } - if ( val_R > m_fMasterPeak_R ) { - m_fMasterPeak_R = val_R; - } - } - } - - // update total frames number - if ( m_audioEngineState == STATE_PLAYING ) { - m_pAudioDriver->m_transport.m_nFrames += nframes; - } - -// float fRenderTime = (renderTime_end.tv_sec - renderTime_start.tv_sec) * 1000.0 + (renderTime_end.tv_usec - renderTime_start.tv_usec) / 1000.0; - float fLadspaTime = - ( ladspaTime_end.tv_sec - ladspaTime_start.tv_sec ) * 1000.0 - + ( ladspaTime_end.tv_usec - ladspaTime_start.tv_usec ) / 1000.0; - - timeval finishTimeval = currentTime2(); - m_fProcessTime = - ( finishTimeval.tv_sec - startTimeval.tv_sec ) * 1000.0 - + ( finishTimeval.tv_usec - startTimeval.tv_usec ) / 1000.0; + // Process LADSPA FX + if ( m_audioEngineState >= STATE_READY ) { + for ( unsigned nFX = 0; nFX < MAX_FX; ++nFX ) { + LadspaFX *pFX = Effects::get_instance()->getLadspaFX( nFX ); + if ( ( pFX ) && ( pFX->isEnabled() ) ) { + pFX->processFX( nframes ); + float *buf_L = NULL; + float *buf_R = NULL; + if ( pFX->getPluginType() == LadspaFX::STEREO_FX ) { + buf_L = pFX->m_pBuffer_L; + buf_R = pFX->m_pBuffer_R; + } else { // MONO FX + buf_L = pFX->m_pBuffer_L; + buf_R = buf_L; + } + for ( unsigned i = 0; i < nframes; ++i ) { + m_pMainBuffer_L[ i ] += buf_L[ i ]; + m_pMainBuffer_R[ i ] += buf_R[ i ]; + if ( buf_L[ i ] > m_fFXPeak_L[nFX] ) + m_fFXPeak_L[nFX] = buf_L[ i ]; + if ( buf_R[ i ] > m_fFXPeak_R[nFX] ) + m_fFXPeak_R[nFX] = buf_R[ i ]; + } + } + } + } +#endif + timeval ladspaTime_end = currentTime2(); + + // update master peaks + float val_L; + float val_R; + if ( m_audioEngineState >= STATE_READY ) { + for ( unsigned i = 0; i < nframes; ++i ) { + val_L = m_pMainBuffer_L[i]; + val_R = m_pMainBuffer_R[i]; + if ( val_L > m_fMasterPeak_L ) { + m_fMasterPeak_L = val_L; + } + if ( val_R > m_fMasterPeak_R ) { + m_fMasterPeak_R = val_R; + } + } + } + + // update total frames number + if ( m_audioEngineState == STATE_PLAYING ) { + m_pAudioDriver->m_transport.m_nFrames += nframes; + } + + // float fRenderTime = (renderTime_end.tv_sec - renderTime_start.tv_sec) * 1000.0 + (renderTime_end.tv_usec - renderTime_start.tv_usec) / 1000.0; + float fLadspaTime = + ( ladspaTime_end.tv_sec - ladspaTime_start.tv_sec ) * 1000.0 + + ( ladspaTime_end.tv_usec - ladspaTime_start.tv_usec ) / 1000.0; + + timeval finishTimeval = currentTime2(); + m_fProcessTime = + ( finishTimeval.tv_sec - startTimeval.tv_sec ) * 1000.0 + + ( finishTimeval.tv_usec - startTimeval.tv_usec ) / 1000.0; - float sampleRate = ( float )m_pAudioDriver->getSampleRate(); - m_fMaxProcessTime = 1000.0 / ( sampleRate / nframes ); + float sampleRate = ( float )m_pAudioDriver->getSampleRate(); + m_fMaxProcessTime = 1000.0 / ( sampleRate / nframes ); #ifdef CONFIG_DEBUG - if ( m_fProcessTime > m_fMaxProcessTime ) { - ___WARNINGLOG( "" ); - ___WARNINGLOG( "----XRUN----" ); - ___WARNINGLOG( QString( "XRUN of %1 msec (%2 > %3)" ) + if ( m_fProcessTime > m_fMaxProcessTime ) { + ___WARNINGLOG( "" ); + ___WARNINGLOG( "----XRUN----" ); + ___WARNINGLOG( QString( "XRUN of %1 msec (%2 > %3)" ) .arg( ( m_fProcessTime - m_fMaxProcessTime ) ) .arg( m_fProcessTime ).arg( m_fMaxProcessTime ) ); - ___WARNINGLOG( QString( "Ladspa process time = %1" ).arg( fLadspaTime ) ); - ___WARNINGLOG( "------------" ); - ___WARNINGLOG( "" ); - // raise xRun event - EventQueue::get_instance()->push_event( EVENT_XRUN, -1 ); - } + ___WARNINGLOG( QString( "Ladspa process time = %1" ).arg( fLadspaTime ) ); + ___WARNINGLOG( "------------" ); + ___WARNINGLOG( "" ); + // raise xRun event + EventQueue::get_instance()->push_event( EVENT_XRUN, -1 ); + } #endif - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); - if ( sendPatternChange ) { - EventQueue::get_instance()->push_event( EVENT_PATTERN_CHANGED, -1 ); - } + if ( sendPatternChange ) { + EventQueue::get_instance()->push_event( EVENT_PATTERN_CHANGED, -1 ); + } - return 0; + return 0; } @@ -928,44 +928,44 @@ void audioEngine_setupLadspaFX( unsigned nBufferSize ) { - //___INFOLOG( "buffersize=" + to_string(nBufferSize) ); + //___INFOLOG( "buffersize=" + to_string(nBufferSize) ); - if ( m_pSong == NULL ) { - //___INFOLOG( "m_pSong=NULL" ); - return; - } - if ( nBufferSize == 0 ) { - ___ERRORLOG( "nBufferSize=0" ); - return; - } + if ( m_pSong == NULL ) { + //___INFOLOG( "m_pSong=NULL" ); + return; + } + if ( nBufferSize == 0 ) { + ___ERRORLOG( "nBufferSize=0" ); + return; + } #ifdef H2CORE_HAVE_LADSPA - for ( unsigned nFX = 0; nFX < MAX_FX; ++nFX ) { - LadspaFX *pFX = Effects::get_instance()->getLadspaFX( nFX ); - if ( pFX == NULL ) { - return; - } - - pFX->deactivate(); - -// delete[] pFX->m_pBuffer_L; -// pFX->m_pBuffer_L = NULL; -// delete[] pFX->m_pBuffer_R; -// pFX->m_pBuffer_R = NULL; -// if ( nBufferSize != 0 ) { - //pFX->m_nBufferSize = nBufferSize; - //pFX->m_pBuffer_L = new float[ nBufferSize ]; - //pFX->m_pBuffer_R = new float[ nBufferSize ]; -// } - - Effects::get_instance()->getLadspaFX( nFX )->connectAudioPorts( - pFX->m_pBuffer_L, - pFX->m_pBuffer_R, - pFX->m_pBuffer_L, - pFX->m_pBuffer_R - ); - pFX->activate(); - } + for ( unsigned nFX = 0; nFX < MAX_FX; ++nFX ) { + LadspaFX *pFX = Effects::get_instance()->getLadspaFX( nFX ); + if ( pFX == NULL ) { + return; + } + + pFX->deactivate(); + + // delete[] pFX->m_pBuffer_L; + // pFX->m_pBuffer_L = NULL; + // delete[] pFX->m_pBuffer_R; + // pFX->m_pBuffer_R = NULL; + // if ( nBufferSize != 0 ) { + //pFX->m_nBufferSize = nBufferSize; + //pFX->m_pBuffer_L = new float[ nBufferSize ]; + //pFX->m_pBuffer_R = new float[ nBufferSize ]; + // } + + Effects::get_instance()->getLadspaFX( nFX )->connectAudioPorts( + pFX->m_pBuffer_L, + pFX->m_pBuffer_R, + pFX->m_pBuffer_L, + pFX->m_pBuffer_R + ); + pFX->activate(); + } #endif } @@ -974,13 +974,13 @@ void audioEngine_renameJackPorts() { #ifdef H2CORE_HAVE_JACK - // renames jack ports - if ( m_pSong == NULL ) { - return; - } - if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { - static_cast< JackOutput* >( m_pAudioDriver )->makeTrackOutputs( m_pSong ); - } + // renames jack ports + if ( m_pSong == NULL ) { + return; + } + if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { + static_cast< JackOutput* >( m_pAudioDriver )->makeTrackOutputs( m_pSong ); + } #endif } @@ -988,89 +988,89 @@ void audioEngine_setSong( Song *newSong ) { - ___WARNINGLOG( QString( "Set song: %1" ).arg( newSong->__name ) ); + ___WARNINGLOG( QString( "Set song: %1" ).arg( newSong->__name ) ); - AudioEngine::get_instance()->lock( RIGHT_HERE ); + AudioEngine::get_instance()->lock( RIGHT_HERE ); - if ( m_audioEngineState == STATE_PLAYING ) { - m_pAudioDriver->stop(); - audioEngine_stop( false ); - } + if ( m_audioEngineState == STATE_PLAYING ) { + m_pAudioDriver->stop(); + audioEngine_stop( false ); + } - // check current state - if ( m_audioEngineState != STATE_PREPARED ) { - ___ERRORLOG( "Error the audio engine is not in PREPARED state" ); - } + // check current state + if ( m_audioEngineState != STATE_PREPARED ) { + ___ERRORLOG( "Error the audio engine is not in PREPARED state" ); + } - m_pPlayingPatterns->clear(); - m_pNextPatterns->clear(); + m_pPlayingPatterns->clear(); + m_pNextPatterns->clear(); - EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 ); - EventQueue::get_instance()->push_event( EVENT_PATTERN_CHANGED, -1 ); - EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); + EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 ); + EventQueue::get_instance()->push_event( EVENT_PATTERN_CHANGED, -1 ); + EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); - //sleep( 1 ); + //sleep( 1 ); - audioEngine_clearNoteQueue(); + audioEngine_clearNoteQueue(); - assert( m_pSong == NULL ); - m_pSong = newSong; + assert( m_pSong == NULL ); + m_pSong = newSong; - // setup LADSPA FX - audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); + // setup LADSPA FX + audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); - // update ticksize - audioEngine_process_checkBPMChanged(); + // update ticksize + audioEngine_process_checkBPMChanged(); - // find the first pattern and set as current - if ( m_pSong->get_pattern_list()->size() > 0 ) { - m_pPlayingPatterns->add( m_pSong->get_pattern_list()->get( 0 ) ); - } + // find the first pattern and set as current + if ( m_pSong->get_pattern_list()->size() > 0 ) { + m_pPlayingPatterns->add( m_pSong->get_pattern_list()->get( 0 ) ); + } - audioEngine_renameJackPorts(); + audioEngine_renameJackPorts(); - m_pAudioDriver->setBpm( m_pSong->__bpm ); + m_pAudioDriver->setBpm( m_pSong->__bpm ); - // change the current audio engine state - m_audioEngineState = STATE_READY; + // change the current audio engine state + m_audioEngineState = STATE_READY; - m_pAudioDriver->locate( 0 ); + m_pAudioDriver->locate( 0 ); - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_READY ); + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_READY ); } void audioEngine_removeSong() { - AudioEngine::get_instance()->lock( RIGHT_HERE ); + AudioEngine::get_instance()->lock( RIGHT_HERE ); - if ( m_audioEngineState == STATE_PLAYING ) { - m_pAudioDriver->stop(); - audioEngine_stop( false ); - } - - // check current state - if ( m_audioEngineState != STATE_READY ) { - ___ERRORLOG( "Error the audio engine is not in READY state" ); - AudioEngine::get_instance()->unlock(); - return; - } - - m_pSong = NULL; - m_pPlayingPatterns->clear(); - m_pNextPatterns->clear(); - - audioEngine_clearNoteQueue(); - - // change the current audio engine state - m_audioEngineState = STATE_PREPARED; - AudioEngine::get_instance()->unlock(); + if ( m_audioEngineState == STATE_PLAYING ) { + m_pAudioDriver->stop(); + audioEngine_stop( false ); + } + + // check current state + if ( m_audioEngineState != STATE_READY ) { + ___ERRORLOG( "Error the audio engine is not in READY state" ); + AudioEngine::get_instance()->unlock(); + return; + } + + m_pSong = NULL; + m_pPlayingPatterns->clear(); + m_pNextPatterns->clear(); + + audioEngine_clearNoteQueue(); + + // change the current audio engine state + m_audioEngineState = STATE_PREPARED; + AudioEngine::get_instance()->unlock(); - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_PREPARED ); + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_PREPARED ); } @@ -1078,315 +1078,327 @@ // return 2 = send pattern changed event!! inline int audioEngine_updateNoteQueue( unsigned nFrames ) { - static int nLastTick = -1; - bool bSendPatternChange = false; - int nMaxTimeHumanize = 2000; - int nLeadLagFactor = m_pAudioDriver->m_transport.m_nTickSize * 5; // 5 ticks - - unsigned int framepos; - if ( m_audioEngineState == STATE_PLAYING ) { - framepos = m_pAudioDriver->m_transport.m_nFrames; - } else { - // use this to support realtime events when not playing - framepos = m_nRealtimeFrames; - } - - int tickNumber_start = 0; - - // We need to look ahead in the song for notes with negative offsets - // from LeadLag or Humanize. When starting from the beginning, we prime - // the note queue with notes between 0 and nFrames plus - // lookahead. lookahead should be equal or greater than the - // nLeadLagFactor + nMaxTimeHumanize. - int lookahead = nLeadLagFactor + nMaxTimeHumanize + 1; - m_nLookaheadFrames = lookahead; - if ( framepos == 0 - || ( m_audioEngineState == STATE_PLAYING - && m_pSong->get_mode() == Song::SONG_MODE - && m_nSongPos == -1 ) ) { - tickNumber_start = (int)( framepos - / m_pAudioDriver->m_transport.m_nTickSize ); - } - else { - tickNumber_start = (int)( (framepos + lookahead) - / m_pAudioDriver->m_transport.m_nTickSize ); - } - int tickNumber_end = (int)( (framepos + nFrames + lookahead) - / m_pAudioDriver->m_transport.m_nTickSize ); - - int tick = tickNumber_start; - -// ___WARNINGLOG( "Lookahead: " + to_string( lookahead -// / m_pAudioDriver->m_transport.m_nTickSize ) ); - // get initial timestamp for first tick - gettimeofday( &m_currentTickTime, NULL ); - - - while ( tick <= tickNumber_end ) { - if ( tick == nLastTick ) { - ++tick; - continue; - } else { - nLastTick = tick; - } - - - // midi events now get put into the m_songNoteQueue as well, - // based on their timestamp - while ( m_midiNoteQueue.size() > 0 ) { - Note *note = m_midiNoteQueue[0]; - - if ( ( int )note->get_position() <= tick ) { - // printf ("tick=%d pos=%d\n", tick, note->getPosition()); - m_midiNoteQueue.pop_front(); - note->get_instrument()->enqueue(); - m_songNoteQueue.push( note ); - } else { - break; - } - } - - if ( m_audioEngineState != STATE_PLAYING ) { - // only keep going if we're playing - continue; - } - -// if ( m_nPatternStartTick == -1 ) { // for debugging pattern mode :s -// ___WARNINGLOG( "m_nPatternStartTick == -1; tick = " -// + to_string( tick ) ); -// } - - - // SONG MODE - bool doErase = m_audioEngineState == STATE_PLAYING - && Preferences::get_instance()->getRecordEvents() - && Preferences::get_instance()->getDestructiveRecord() - && Preferences::get_instance()->m_nRecPreDelete == 0; - if ( m_pSong->get_mode() == Song::SONG_MODE ) { - if ( m_pSong->get_pattern_group_vector()->size() == 0 ) { - // there's no song!! - ___ERRORLOG( "no patterns in song." ); - m_pAudioDriver->stop(); - return -1; - } - - m_nSongPos = findPatternInTick( tick, - m_pSong->is_loop_enabled(), - &m_nPatternStartTick ); - if ( m_nSongSizeInTicks != 0 ) { - m_nPatternTickPosition = ( tick - m_nPatternStartTick ) - % m_nSongSizeInTicks; - } else { - m_nPatternTickPosition = tick - m_nPatternStartTick; - } - - - if ( m_nPatternTickPosition == 0 ) { - bSendPatternChange = true; - } - -// PatternList *pPatternList = -// (*(m_pSong->getPatternGroupVector()))[m_nSongPos]; - if ( m_nSongPos == -1 ) { - ___INFOLOG( "song pos = -1" ); - if ( m_pSong->is_loop_enabled() == true ) { - m_nSongPos = findPatternInTick( 0, - true, - &m_nPatternStartTick ); - } else { - - ___INFOLOG( "End of Song" ); - - if( Hydrogen::get_instance()->getMidiOutput() != NULL ){ - Hydrogen::get_instance()->getMidiOutput()->handleQueueAllNoteOff(); - } - - return -1; - } - } - PatternList *pPatternList = ( *( m_pSong->get_pattern_group_vector() ) )[m_nSongPos]; - m_pPlayingPatterns->clear(); - for ( int i=0; i< pPatternList->size(); ++i ) { - Pattern* pattern = pPatternList->get(i); - m_pPlayingPatterns->add( pattern ); - pattern->extand_with_flattened_virtual_patterns( m_pPlayingPatterns ); - } - // Set destructive record depending on punch area - doErase = doErase && Preferences::get_instance()->inPunchArea(m_nSongPos); - } - // PATTERN MODE - else if ( m_pSong->get_mode() == Song::PATTERN_MODE ) { - // per ora considero solo il primo pattern, se ce ne - // saranno piu' di uno bisognera' prendere quello piu' - // piccolo - - //m_nPatternTickPosition = tick % m_pCurrentPattern->getSize(); - int nPatternSize = MAX_NOTES; - - - if ( Preferences::get_instance()->patternModePlaysSelected() ) - { - m_pPlayingPatterns->clear(); - Pattern * pattern = m_pSong->get_pattern_list()->get(m_nSelectedPatternNumber); - m_pPlayingPatterns->add( pattern ); - pattern->extand_with_flattened_virtual_patterns( m_pPlayingPatterns ); - } - - - if ( m_pPlayingPatterns->size() != 0 ) { - Pattern *pFirstPattern = m_pPlayingPatterns->get( 0 ); - nPatternSize = pFirstPattern->get_length(); - } - - if ( nPatternSize == 0 ) { - ___ERRORLOG( "nPatternSize == 0" ); - } - - if ( ( tick == m_nPatternStartTick + nPatternSize ) - || ( m_nPatternStartTick == -1 ) ) { - if ( m_pNextPatterns->size() > 0 ) { - Pattern * p; - for ( uint i = 0; - i < m_pNextPatterns->size(); - i++ ) { - p = m_pNextPatterns->get( i ); -// ___WARNINGLOG( QString( "Got pattern # %1" ) -// .arg( i + 1 ) ); - // if the pattern isn't playing - // already, start it now. - if ( ( m_pPlayingPatterns->del( p ) ) == NULL ) { - m_pPlayingPatterns->add( p ); - } - } - m_pNextPatterns->clear(); - bSendPatternChange = true; - } - if ( m_nPatternStartTick == -1 ) { - m_nPatternStartTick = tick - (tick % nPatternSize); -// ___WARNINGLOG( "set Pattern Start Tick to " -// + to_string( m_nPatternStartTick ) ); - } else { - m_nPatternStartTick = tick; - } - } - m_nPatternTickPosition = tick - m_nPatternStartTick; - if ( m_nPatternTickPosition > nPatternSize ) { - m_nPatternTickPosition = tick % nPatternSize; - } - } - - // metronome -// if ( ( m_nPatternStartTick == tick ) -// || ( ( tick - m_nPatternStartTick ) % 48 == 0 ) ) { - if ( m_nPatternTickPosition % 48 == 0 ) { - float fPitch; - float fVelocity; -// ___INFOLOG( "Beat: " + to_string(m_nPatternTickPosition / 48 + 1) -// + "@ " + to_string( tick ) ); - if ( m_nPatternTickPosition == 0 ) { - fPitch = 3; - fVelocity = 1.0; - EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 ); - } else { - fPitch = 0; - fVelocity = 0.8; - EventQueue::get_instance()->push_event( EVENT_METRONOME, 0 ); - } - if ( Preferences::get_instance()->m_bUseMetronome ) { - m_pMetronomeInstrument->set_volume( - Preferences::get_instance()->m_fMetronomeVolume - ); - Note *pMetronomeNote = new Note( m_pMetronomeInstrument, - tick, - fVelocity, - 0.5, - 0.5, - -1, - fPitch - ); - m_pMetronomeInstrument->enqueue(); - m_songNoteQueue.push( pMetronomeNote ); - } - } - - // update the notes queue - if ( m_pPlayingPatterns->size() != 0 ) { - for ( unsigned nPat = 0 ; - nPat < m_pPlayingPatterns->size() ; - ++nPat ) { - Pattern *pPattern = m_pPlayingPatterns->get( nPat ); - assert( pPattern != NULL ); - Pattern::notes_t* notes = (Pattern::notes_t*)pPattern->get_notes(); - // Delete notes before attempting to play them - if ( doErase ) { - FOREACH_NOTE_IT_BOUND(notes,it,m_nPatternTickPosition) { - Note* pNote = it->second; - assert( pNote != NULL ); - if ( pNote->get_just_recorded() == false ) { - delete pNote; - notes->erase( it ); - } - } - } - - // Now play notes - FOREACH_NOTE_CST_IT_BOUND(notes,it,m_nPatternTickPosition) { - Note *pNote = it->second; - if ( pNote ) { - pNote->set_just_recorded( false ); - int nOffset = 0; - - // Swing - float fSwingFactor = m_pSong->get_swing_factor(); - - if ( ( ( m_nPatternTickPosition % 12 ) == 0 ) - && ( ( m_nPatternTickPosition % 24 ) != 0 ) ) { - // da l'accento al tick 4, 12, 20, 36... - nOffset += ( int )( - 6.0 - * m_pAudioDriver->m_transport.m_nTickSize - * fSwingFactor - ); - } - - // Humanize - Time parameter - if ( m_pSong->get_humanize_time_value() != 0 ) { - nOffset += ( int )( - getGaussian( 0.3 ) - * m_pSong->get_humanize_time_value() - * nMaxTimeHumanize - ); - } - //~ - // Lead or Lag - timing parameter - nOffset += (int) ( pNote->get_lead_lag() - * nLeadLagFactor); - //~ - - if((tick == 0) && (nOffset < 0)) { - nOffset = 0; - } - Note *pCopiedNote = new Note( pNote ); - pCopiedNote->set_position( tick ); - - // humanize time - pCopiedNote->set_humanize_delay( nOffset ); - pNote->get_instrument()->enqueue(); - m_songNoteQueue.push( pCopiedNote ); - //pCopiedNote->dumpInfo(); - } - } - } - } - ++tick; - } - - - // audioEngine_process must send the pattern change event after mutex unlock - if ( bSendPatternChange ) { - return 2; - } - return 0; + static int nLastTick = -1; + bool bSendPatternChange = false; + int nMaxTimeHumanize = 2000; + int nLeadLagFactor = m_pAudioDriver->m_transport.m_nTickSize * 5; // 5 ticks + + unsigned int framepos; + if ( m_audioEngineState == STATE_PLAYING ) { + framepos = m_pAudioDriver->m_transport.m_nFrames; + } else { + // use this to support realtime events when not playing + framepos = m_nRealtimeFrames; + } + + int tickNumber_start = 0; + + // We need to look ahead in the song for notes with negative offsets + // from LeadLag or Humanize. When starting from the beginning, we prime + // the note queue with notes between 0 and nFrames plus + // lookahead. lookahead should be equal or greater than the + // nLeadLagFactor + nMaxTimeHumanize. + int lookahead = nLeadLagFactor + nMaxTimeHumanize + 1; + m_nLookaheadFrames = lookahead; + if ( framepos == 0 + || ( m_audioEngineState == STATE_PLAYING + && m_pSong->get_mode() == Song::SONG_MODE + && m_nSongPos == -1 ) ) { + tickNumber_start = (int)( framepos + / m_pAudioDriver->m_transport.m_nTickSize ); + } + else { + tickNumber_start = (int)( (framepos + lookahead) + / m_pAudioDriver->m_transport.m_nTickSize ); + } + int tickNumber_end = (int)( (framepos + nFrames + lookahead) + / m_pAudioDriver->m_transport.m_nTickSize ); + + int tick = tickNumber_start; + + // ___WARNINGLOG( "Lookahead: " + to_string( lookahead + // / m_pAudioDriver->m_transport.m_nTickSize ) ); + // get initial timestamp for first tick + gettimeofday( &m_currentTickTime, NULL ); + + + while ( tick <= tickNumber_end ) { + if ( tick == nLastTick ) { + ++tick; + continue; + } else { + nLastTick = tick; + } + + + // midi events now get put into the m_songNoteQueue as well, + // based on their timestamp + while ( m_midiNoteQueue.size() > 0 ) { + Note *note = m_midiNoteQueue[0]; + + if ( ( int )note->get_position() <= tick ) { + // printf ("tick=%d pos=%d\n", tick, note->getPosition()); + m_midiNoteQueue.pop_front(); + note->get_instrument()->enqueue(); + m_songNoteQueue.push( note ); + } else { + break; + } + } + + if ( m_audioEngineState != STATE_PLAYING ) { + // only keep going if we're playing + continue; + } + + // if ( m_nPatternStartTick == -1 ) { // for debugging pattern mode :s + // ___WARNINGLOG( "m_nPatternStartTick == -1; tick = " + // + to_string( tick ) ); + // } + + + // SONG MODE + bool doErase = m_audioEngineState == STATE_PLAYING + && Preferences::get_instance()->getRecordEvents() + && Preferences::get_instance()->getDestructiveRecord() + && Preferences::get_instance()->m_nRecPreDelete == 0; + if ( m_pSong->get_mode() == Song::SONG_MODE ) { + if ( m_pSong->get_pattern_group_vector()->size() == 0 ) { + // there's no song!! + ___ERRORLOG( "no patterns in song." ); + m_pAudioDriver->stop(); + return -1; + } + + m_nSongPos = findPatternInTick( tick, + m_pSong->is_loop_enabled(), + &m_nPatternStartTick ); + if ( m_nSongSizeInTicks != 0 ) { + m_nPatternTickPosition = ( tick - m_nPatternStartTick ) + % m_nSongSizeInTicks; + } else { + m_nPatternTickPosition = tick - m_nPatternStartTick; + } + + + if ( m_nPatternTickPosition == 0 ) { + bSendPatternChange = true; + } + + // PatternList *pPatternList = + // (*(m_pSong->getPatternGroupVector()))[m_nSongPos]; + if ( m_nSongPos == -1 ) { + ___INFOLOG( "song pos = -1" ); + if ( m_pSong->is_loop_enabled() == true ) { + m_nSongPos = findPatternInTick( 0, + true, + &m_nPatternStartTick ); + } else { + + ___INFOLOG( "End of Song" ); + + if( Hydrogen::get_instance()->getMidiOutput() != NULL ){ + Hydrogen::get_instance()->getMidiOutput()->handleQueueAllNoteOff(); + } + + return -1; + } + } + PatternList *pPatternList = ( *( m_pSong->get_pattern_group_vector() ) )[m_nSongPos]; + m_pPlayingPatterns->clear(); + for ( int i=0; i< pPatternList->size(); ++i ) { + Pattern* pattern = pPatternList->get(i); + m_pPlayingPatterns->add( pattern ); + pattern->extand_with_flattened_virtual_patterns( m_pPlayingPatterns ); + } + // Set destructive record depending on punch area + doErase = doErase && Preferences::get_instance()->inPunchArea(m_nSongPos); + } + // PATTERN MODE + else if ( m_pSong->get_mode() == Song::PATTERN_MODE ) { + // per ora considero solo il primo pattern, se ce ne + // saranno piu' di uno bisognera' prendere quello piu' + // piccolo + + //m_nPatternTickPosition = tick % m_pCurrentPattern->getSize(); + int nPatternSize = MAX_NOTES; + + + if ( Preferences::get_instance()->patternModePlaysSelected() ) + { + m_pPlayingPatterns->clear(); + Pattern * pattern = m_pSong->get_pattern_list()->get(m_nSelectedPatternNumber); + m_pPlayingPatterns->add( pattern ); + pattern->extand_with_flattened_virtual_patterns( m_pPlayingPatterns ); + } + + + if ( m_pPlayingPatterns->size() != 0 ) { + Pattern *pFirstPattern = m_pPlayingPatterns->get( 0 ); + nPatternSize = pFirstPattern->get_length(); + } + + if ( nPatternSize == 0 ) { + ___ERRORLOG( "nPatternSize == 0" ); + } + + if ( ( tick == m_nPatternStartTick + nPatternSize ) + || ( m_nPatternStartTick == -1 ) ) { + if ( m_pNextPatterns->size() > 0 ) { + Pattern * p; + for ( uint i = 0; + i < m_pNextPatterns->size(); + i++ ) { + p = m_pNextPatterns->get( i ); + // ___WARNINGLOG( QString( "Got pattern # %1" ) + // .arg( i + 1 ) ); + // if the pattern isn't playing + // already, start it now. + if ( ( m_pPlayingPatterns->del( p ) ) == NULL ) { + m_pPlayingPatterns->add( p ); + } + } + m_pNextPatterns->clear(); + bSendPatternChange = true; + } + if ( m_nPatternStartTick == -1 ) { + m_nPatternStartTick = tick - (tick % nPatternSize); + // ___WARNINGLOG( "set Pattern Start Tick to " + // + to_string( m_nPatternStartTick ) ); + } else { + m_nPatternStartTick = tick; + } + } + m_nPatternTickPosition = tick - m_nPatternStartTick; + if ( m_nPatternTickPosition > nPatternSize ) { + m_nPatternTickPosition = tick % nPatternSize; + } + } + + // metronome + // if ( ( m_nPatternStartTick == tick ) + // || ( ( tick - m_nPatternStartTick ) % 48 == 0 ) ) { + if ( m_nPatternTickPosition % 48 == 0 ) { + float fPitch; + float fVelocity; + // ___INFOLOG( "Beat: " + to_string(m_nPatternTickPosition / 48 + 1) + // + "@ " + to_string( tick ) ); + if ( m_nPatternTickPosition == 0 ) { + fPitch = 3; + fVelocity = 1.0; + EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 ); + } else { + fPitch = 0; + fVelocity = 0.8; + EventQueue::get_instance()->push_event( EVENT_METRONOME, 0 ); + } + if ( Preferences::get_instance()->m_bUseMetronome ) { + m_pMetronomeInstrument->set_volume( + Preferences::get_instance()->m_fMetronomeVolume + ); + Note *pMetronomeNote = new Note( m_pMetronomeInstrument, + tick, + fVelocity, + 0.5, + 0.5, + -1, + fPitch + ); + m_pMetronomeInstrument->enqueue(); + m_songNoteQueue.push( pMetronomeNote ); + } + } + + // update the notes queue + if ( m_pPlayingPatterns->size() != 0 ) { + for ( unsigned nPat = 0 ; + nPat < m_pPlayingPatterns->size() ; + ++nPat ) { + Pattern *pPattern = m_pPlayingPatterns->get( nPat ); + assert( pPattern != NULL ); + Pattern::notes_t* notes = (Pattern::notes_t*)pPattern->get_notes(); + // Delete notes before attempting to play them + if ( doErase ) { + FOREACH_NOTE_IT_BOUND(notes,it,m_nPatternTickPosition) { + Note* pNote = it->second; + assert( pNote != NULL ); + if ( pNote->get_just_recorded() == false ) { + EventQueue::AddMidiNoteVector noteAction; + noteAction.m_column = pNote->get_position(); + noteAction.m_row = pNote->get_instrument_id(); + noteAction.m_pattern = nPat; + noteAction.f_velocity = pNote->get_velocity(); + noteAction.f_pan_L = pNote->get_pan_l(); + noteAction.f_pan_R = pNote->get_pan_r(); + noteAction.m_length = -1; + noteAction.no_octaveKeyVal = pNote->get_octave(); + noteAction.nk_noteKeyVal = pNote->get_key(); + noteAction.b_isInstrumentMode = false; + noteAction.b_isMidi = false; + noteAction.b_noteExist = false; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + } + } + } + + // Now play notes + FOREACH_NOTE_CST_IT_BOUND(notes,it,m_nPatternTickPosition) { + Note *pNote = it->second; + if ( pNote ) { + pNote->set_just_recorded( false ); + int nOffset = 0; + + // Swing + float fSwingFactor = m_pSong->get_swing_factor(); + + if ( ( ( m_nPatternTickPosition % 12 ) == 0 ) + && ( ( m_nPatternTickPosition % 24 ) != 0 ) ) { + // da l'accento al tick 4, 12, 20, 36... + nOffset += ( int )( + 6.0 + * m_pAudioDriver->m_transport.m_nTickSize + * fSwingFactor + ); + } + + // Humanize - Time parameter + if ( m_pSong->get_humanize_time_value() != 0 ) { + nOffset += ( int )( + getGaussian( 0.3 ) + * m_pSong->get_humanize_time_value() + * nMaxTimeHumanize + ); + } + //~ + // Lead or Lag - timing parameter + nOffset += (int) ( pNote->get_lead_lag() + * nLeadLagFactor); + //~ + + if((tick == 0) && (nOffset < 0)) { + nOffset = 0; + } + Note *pCopiedNote = new Note( pNote ); + pCopiedNote->set_position( tick ); + + // humanize time + pCopiedNote->set_humanize_delay( nOffset ); + pNote->get_instrument()->enqueue(); + m_songNoteQueue.push( pCopiedNote ); + //pCopiedNote->dumpInfo(); + } + } + } + } + ++tick; + } + + + // audioEngine_process must send the pattern change event after mutex unlock + if ( bSendPatternChange ) { + return 2; + } + return 0; } @@ -1394,101 +1406,101 @@ /// restituisce l'indice relativo al patternGroup in base al tick inline int findPatternInTick( int nTick, bool bLoopMode, int *pPatternStartTick ) { - assert( m_pSong ); + assert( m_pSong ); - int nTotalTick = 0; - m_nSongSizeInTicks = 0; + int nTotalTick = 0; + m_nSongSizeInTicks = 0; - std::vector *pPatternColumns = m_pSong->get_pattern_group_vector(); - int nColumns = pPatternColumns->size(); + std::vector *pPatternColumns = m_pSong->get_pattern_group_vector(); + int nColumns = pPatternColumns->size(); - int nPatternSize; - for ( int i = 0; i < nColumns; ++i ) { - PatternList *pColumn = ( *pPatternColumns )[ i ]; - if ( pColumn->size() != 0 ) { - // tengo in considerazione solo il primo pattern. I - // pattern nel gruppo devono avere la stessa lunghezza. - nPatternSize = pColumn->get( 0 )->get_length(); - } else { - nPatternSize = MAX_NOTES; - } - - if ( ( nTick >= nTotalTick ) && ( nTick < nTotalTick + nPatternSize ) ) { - ( *pPatternStartTick ) = nTotalTick; - return i; - } - nTotalTick += nPatternSize; - } - - if ( bLoopMode ) { - m_nSongSizeInTicks = nTotalTick; - int nLoopTick = 0; - if ( m_nSongSizeInTicks != 0 ) { - nLoopTick = nTick % m_nSongSizeInTicks; - } - nTotalTick = 0; - for ( int i = 0; i < nColumns; ++i ) { - PatternList *pColumn = ( *pPatternColumns )[ i ]; - if ( pColumn->size() != 0 ) { - // tengo in considerazione solo il primo - // pattern. I pattern nel gruppo devono avere la - // stessa lunghezza. - nPatternSize = pColumn->get( 0 )->get_length(); - } else { - nPatternSize = MAX_NOTES; - } - - if ( ( nLoopTick >= nTotalTick ) - && ( nLoopTick < nTotalTick + nPatternSize ) ) { - ( *pPatternStartTick ) = nTotalTick; - return i; - } - nTotalTick += nPatternSize; - } - } - - QString err = QString( "[findPatternInTick] tick = %1. No pattern found" ).arg( QString::number(nTick) ); - ___ERRORLOG( err ); - return -1; + int nPatternSize; + for ( int i = 0; i < nColumns; ++i ) { + PatternList *pColumn = ( *pPatternColumns )[ i ]; + if ( pColumn->size() != 0 ) { + // tengo in considerazione solo il primo pattern. I + // pattern nel gruppo devono avere la stessa lunghezza. + nPatternSize = pColumn->get( 0 )->get_length(); + } else { + nPatternSize = MAX_NOTES; + } + + if ( ( nTick >= nTotalTick ) && ( nTick < nTotalTick + nPatternSize ) ) { + ( *pPatternStartTick ) = nTotalTick; + return i; + } + nTotalTick += nPatternSize; + } + + if ( bLoopMode ) { + m_nSongSizeInTicks = nTotalTick; + int nLoopTick = 0; + if ( m_nSongSizeInTicks != 0 ) { + nLoopTick = nTick % m_nSongSizeInTicks; + } + nTotalTick = 0; + for ( int i = 0; i < nColumns; ++i ) { + PatternList *pColumn = ( *pPatternColumns )[ i ]; + if ( pColumn->size() != 0 ) { + // tengo in considerazione solo il primo + // pattern. I pattern nel gruppo devono avere la + // stessa lunghezza. + nPatternSize = pColumn->get( 0 )->get_length(); + } else { + nPatternSize = MAX_NOTES; + } + + if ( ( nLoopTick >= nTotalTick ) + && ( nLoopTick < nTotalTick + nPatternSize ) ) { + ( *pPatternStartTick ) = nTotalTick; + return i; + } + nTotalTick += nPatternSize; + } + } + + QString err = QString( "[findPatternInTick] tick = %1. No pattern found" ).arg( QString::number(nTick) ); + ___ERRORLOG( err ); + return -1; } void audioEngine_noteOn( Note *note ) { - // check current state - if ( ( m_audioEngineState != STATE_READY ) - && ( m_audioEngineState != STATE_PLAYING ) ) { - ___ERRORLOG( "Error the audio engine is not in READY state" ); - delete note; - return; - } + // check current state + if ( ( m_audioEngineState != STATE_READY ) + && ( m_audioEngineState != STATE_PLAYING ) ) { + ___ERRORLOG( "Error the audio engine is not in READY state" ); + delete note; + return; + } - m_midiNoteQueue.push_back( note ); + m_midiNoteQueue.push_back( note ); } /* void audioEngine_noteOff( Note *note ) { - if ( note == NULL ) { - ___ERRORLOG( "Error, note == NULL" ); - } - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - // check current state - if ( ( m_audioEngineState != STATE_READY ) - && ( m_audioEngineState != STATE_PLAYING ) ) { - ___ERRORLOG( "Error the audio engine is not in READY state" ); - delete note; - AudioEngine::get_instance()->unlock(); - return; - } + if ( note == NULL ) { + ___ERRORLOG( "Error, note == NULL" ); + } + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + // check current state + if ( ( m_audioEngineState != STATE_READY ) + && ( m_audioEngineState != STATE_PLAYING ) ) { + ___ERRORLOG( "Error the audio engine is not in READY state" ); + delete note; + AudioEngine::get_instance()->unlock(); + return; + } // AudioEngine::get_instance()->get_sampler()->note_off( note ); - AudioEngine::get_instance()->unlock(); - delete note; + AudioEngine::get_instance()->unlock(); + delete note; } */ @@ -1502,215 +1514,215 @@ AudioOutput* createDriver( const QString& sDriver ) { - ___INFOLOG( QString( "Driver: '%1'" ).arg( sDriver ) ); - Preferences *pPref = Preferences::get_instance(); - AudioOutput *pDriver = NULL; - - if ( sDriver == "Oss" ) { - pDriver = new OssDriver( audioEngine_process ); - if ( pDriver->class_name() == NullDriver::class_name() ) { - delete pDriver; - pDriver = NULL; - } - } else if ( sDriver == "Jack" ) { - pDriver = new JackOutput( audioEngine_process ); - if ( pDriver->class_name() == NullDriver::class_name() ) { - delete pDriver; - pDriver = NULL; - } else { + ___INFOLOG( QString( "Driver: '%1'" ).arg( sDriver ) ); + Preferences *pPref = Preferences::get_instance(); + AudioOutput *pDriver = NULL; + + if ( sDriver == "Oss" ) { + pDriver = new OssDriver( audioEngine_process ); + if ( pDriver->class_name() == NullDriver::class_name() ) { + delete pDriver; + pDriver = NULL; + } + } else if ( sDriver == "Jack" ) { + pDriver = new JackOutput( audioEngine_process ); + if ( pDriver->class_name() == NullDriver::class_name() ) { + delete pDriver; + pDriver = NULL; + } else { #ifdef H2CORE_HAVE_JACK - static_cast(pDriver)->setConnectDefaults( - Preferences::get_instance()->m_bJackConnectDefaults - ); -#endif - } - } else if ( sDriver == "Alsa" ) { - pDriver = new AlsaAudioDriver( audioEngine_process ); - if ( pDriver->class_name() == NullDriver::class_name() ) { - delete pDriver; - pDriver = NULL; - } - } else if ( sDriver == "PortAudio" ) { - pDriver = new PortAudioDriver( audioEngine_process ); - if ( pDriver->class_name() == NullDriver::class_name() ) { - delete pDriver; - pDriver = NULL; - } - } -//#ifdef Q_OS_MACX - else if ( sDriver == "CoreAudio" ) { - ___INFOLOG( "Creating CoreAudioDriver" ); - pDriver = new CoreAudioDriver( audioEngine_process ); - if ( pDriver->class_name() == NullDriver::class_name() ) { - delete pDriver; - pDriver = NULL; - } - } -//#endif - else if ( sDriver == "Fake" ) { - ___WARNINGLOG( "*** Using FAKE audio driver ***" ); - pDriver = new FakeDriver( audioEngine_process ); - } else { - ___ERRORLOG( "Unknown driver " + sDriver ); - audioEngine_raiseError( Hydrogen::UNKNOWN_DRIVER ); - } - - if ( pDriver ) { - // initialize the audio driver - int res = pDriver->init( pPref->m_nBufferSize ); - if ( res != 0 ) { - ___ERRORLOG( "Error starting audio driver [audioDriver::init()]" ); - delete pDriver; - pDriver = NULL; - } - } + static_cast(pDriver)->setConnectDefaults( + Preferences::get_instance()->m_bJackConnectDefaults + ); +#endif + } + } else if ( sDriver == "Alsa" ) { + pDriver = new AlsaAudioDriver( audioEngine_process ); + if ( pDriver->class_name() == NullDriver::class_name() ) { + delete pDriver; + pDriver = NULL; + } + } else if ( sDriver == "PortAudio" ) { + pDriver = new PortAudioDriver( audioEngine_process ); + if ( pDriver->class_name() == NullDriver::class_name() ) { + delete pDriver; + pDriver = NULL; + } + } + //#ifdef Q_OS_MACX + else if ( sDriver == "CoreAudio" ) { + ___INFOLOG( "Creating CoreAudioDriver" ); + pDriver = new CoreAudioDriver( audioEngine_process ); + if ( pDriver->class_name() == NullDriver::class_name() ) { + delete pDriver; + pDriver = NULL; + } + } + //#endif + else if ( sDriver == "Fake" ) { + ___WARNINGLOG( "*** Using FAKE audio driver ***" ); + pDriver = new FakeDriver( audioEngine_process ); + } else { + ___ERRORLOG( "Unknown driver " + sDriver ); + audioEngine_raiseError( Hydrogen::UNKNOWN_DRIVER ); + } + + if ( pDriver ) { + // initialize the audio driver + int res = pDriver->init( pPref->m_nBufferSize ); + if ( res != 0 ) { + ___ERRORLOG( "Error starting audio driver [audioDriver::init()]" ); + delete pDriver; + pDriver = NULL; + } + } - return pDriver; + return pDriver; } /// Start all audio drivers void audioEngine_startAudioDrivers() { - Preferences *preferencesMng = Preferences::get_instance(); + Preferences *preferencesMng = Preferences::get_instance(); - AudioEngine::get_instance()->lock( RIGHT_HERE ); - QMutexLocker mx(&mutex_OutputPointer); + AudioEngine::get_instance()->lock( RIGHT_HERE ); + QMutexLocker mx(&mutex_OutputPointer); - ___INFOLOG( "[audioEngine_startAudioDrivers]" ); + ___INFOLOG( "[audioEngine_startAudioDrivers]" ); - // check current state - if ( m_audioEngineState != STATE_INITIALIZED ) { - ___ERRORLOG( QString( "Error the audio engine is not in INITIALIZED" + // check current state + if ( m_audioEngineState != STATE_INITIALIZED ) { + ___ERRORLOG( QString( "Error the audio engine is not in INITIALIZED" " state. state=%1" ) .arg( m_audioEngineState ) ); - AudioEngine::get_instance()->unlock(); - return; - } - - if ( m_pAudioDriver ) { // check if the audio m_pAudioDriver is still alive - ___ERRORLOG( "The audio driver is still alive" ); - } - if ( m_pMidiDriver ) { // check if midi driver is still alive - ___ERRORLOG( "The MIDI driver is still active" ); - } - - - QString sAudioDriver = preferencesMng->m_sAudioDriver; -// sAudioDriver = "Auto"; - if ( sAudioDriver == "Auto" ) { - if ( ( m_pAudioDriver = createDriver( "Jack" ) ) == NULL ) { - if ( ( m_pAudioDriver = createDriver( "Alsa" ) ) == NULL ) { - if ( ( m_pAudioDriver = createDriver( "CoreAudio" ) ) == NULL ) { - if ( ( m_pAudioDriver = createDriver( "PortAudio" ) ) == NULL ) { - if ( ( m_pAudioDriver = createDriver( "Oss" ) ) == NULL ) { - audioEngine_raiseError( Hydrogen::ERROR_STARTING_DRIVER ); - ___ERRORLOG( "Error starting audio driver" ); - ___ERRORLOG( "Using the NULL output audio driver" ); - - // use the NULL output driver - m_pAudioDriver = new NullDriver( audioEngine_process ); - m_pAudioDriver->init( 0 ); - } - } - } - } - } - } else { - m_pAudioDriver = createDriver( sAudioDriver ); - if ( m_pAudioDriver == NULL ) { - audioEngine_raiseError( Hydrogen::ERROR_STARTING_DRIVER ); - ___ERRORLOG( "Error starting audio driver" ); - ___ERRORLOG( "Using the NULL output audio driver" ); - - // use the NULL output driver - m_pAudioDriver = new NullDriver( audioEngine_process ); - m_pAudioDriver->init( 0 ); - } - } + AudioEngine::get_instance()->unlock(); + return; + } + + if ( m_pAudioDriver ) { // check if the audio m_pAudioDriver is still alive + ___ERRORLOG( "The audio driver is still alive" ); + } + if ( m_pMidiDriver ) { // check if midi driver is still alive + ___ERRORLOG( "The MIDI driver is still active" ); + } + + + QString sAudioDriver = preferencesMng->m_sAudioDriver; + // sAudioDriver = "Auto"; + if ( sAudioDriver == "Auto" ) { + if ( ( m_pAudioDriver = createDriver( "Jack" ) ) == NULL ) { + if ( ( m_pAudioDriver = createDriver( "Alsa" ) ) == NULL ) { + if ( ( m_pAudioDriver = createDriver( "CoreAudio" ) ) == NULL ) { + if ( ( m_pAudioDriver = createDriver( "PortAudio" ) ) == NULL ) { + if ( ( m_pAudioDriver = createDriver( "Oss" ) ) == NULL ) { + audioEngine_raiseError( Hydrogen::ERROR_STARTING_DRIVER ); + ___ERRORLOG( "Error starting audio driver" ); + ___ERRORLOG( "Using the NULL output audio driver" ); + + // use the NULL output driver + m_pAudioDriver = new NullDriver( audioEngine_process ); + m_pAudioDriver->init( 0 ); + } + } + } + } + } + } else { + m_pAudioDriver = createDriver( sAudioDriver ); + if ( m_pAudioDriver == NULL ) { + audioEngine_raiseError( Hydrogen::ERROR_STARTING_DRIVER ); + ___ERRORLOG( "Error starting audio driver" ); + ___ERRORLOG( "Using the NULL output audio driver" ); + + // use the NULL output driver + m_pAudioDriver = new NullDriver( audioEngine_process ); + m_pAudioDriver->init( 0 ); + } + } - if ( preferencesMng->m_sMidiDriver == "ALSA" ) { + if ( preferencesMng->m_sMidiDriver == "ALSA" ) { #ifdef H2CORE_HAVE_ALSA - // Create MIDI driver - AlsaMidiDriver *alsaMidiDriver = new AlsaMidiDriver(); - m_pMidiDriverOut = alsaMidiDriver; - m_pMidiDriver = alsaMidiDriver; - m_pMidiDriver->open(); - m_pMidiDriver->setActive( true ); + // Create MIDI driver + AlsaMidiDriver *alsaMidiDriver = new AlsaMidiDriver(); + m_pMidiDriverOut = alsaMidiDriver; + m_pMidiDriver = alsaMidiDriver; + m_pMidiDriver->open(); + m_pMidiDriver->setActive( true ); #endif - } else if ( preferencesMng->m_sMidiDriver == "PortMidi" ) { + } else if ( preferencesMng->m_sMidiDriver == "PortMidi" ) { #ifdef H2CORE_HAVE_PORTMIDI - m_pMidiDriver = new PortMidiDriver(); - m_pMidiDriver->open(); - m_pMidiDriver->setActive( true ); + m_pMidiDriver = new PortMidiDriver(); + m_pMidiDriver->open(); + m_pMidiDriver->setActive( true ); #endif - } else if ( preferencesMng->m_sMidiDriver == "CoreMidi" ) { + } else if ( preferencesMng->m_sMidiDriver == "CoreMidi" ) { #ifdef H2CORE_HAVE_COREMIDI - m_pMidiDriver = new CoreMidiDriver(); - m_pMidiDriver->open(); - m_pMidiDriver->setActive( true ); + m_pMidiDriver = new CoreMidiDriver(); + m_pMidiDriver->open(); + m_pMidiDriver->setActive( true ); #endif - } else if ( preferencesMng->m_sMidiDriver == "JackMidi" ) { + } else if ( preferencesMng->m_sMidiDriver == "JackMidi" ) { #ifdef H2CORE_HAVE_JACK - JackMidiDriver *jackMidiDriver = new JackMidiDriver(); - m_pMidiDriverOut = jackMidiDriver; - m_pMidiDriver = jackMidiDriver; - m_pMidiDriver->open(); - m_pMidiDriver->setActive( true ); -#endif - } - - // change the current audio engine state - if ( m_pSong == NULL ) { - m_audioEngineState = STATE_PREPARED; - } else { - m_audioEngineState = STATE_READY; - } - - - if ( m_pSong ) { - m_pAudioDriver->setBpm( m_pSong->__bpm ); - } - - if ( m_audioEngineState == STATE_PREPARED ) { - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_PREPARED ); - } else if ( m_audioEngineState == STATE_READY ) { - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_READY ); - } - - // Unlocking earlier might execute the jack process() callback before we - // are fully initialized. - mx.unlock(); - AudioEngine::get_instance()->unlock(); - - if ( m_pAudioDriver ) { - int res = m_pAudioDriver->connect(); - if ( res != 0 ) { - audioEngine_raiseError( Hydrogen::ERROR_STARTING_DRIVER ); - ___ERRORLOG( "Error starting audio driver [audioDriver::connect()]" ); - ___ERRORLOG( "Using the NULL output audio driver" ); - - mx.relock(); - delete m_pAudioDriver; - m_pAudioDriver = new NullDriver( audioEngine_process ); - mx.unlock(); - m_pAudioDriver->init( 0 ); - m_pAudioDriver->connect(); - } - - if ( ( m_pMainBuffer_L = m_pAudioDriver->getOut_L() ) == NULL ) { - ___ERRORLOG( "m_pMainBuffer_L == NULL" ); - } - if ( ( m_pMainBuffer_R = m_pAudioDriver->getOut_R() ) == NULL ) { - ___ERRORLOG( "m_pMainBuffer_R == NULL" ); - } + JackMidiDriver *jackMidiDriver = new JackMidiDriver(); + m_pMidiDriverOut = jackMidiDriver; + m_pMidiDriver = jackMidiDriver; + m_pMidiDriver->open(); + m_pMidiDriver->setActive( true ); +#endif + } + + // change the current audio engine state + if ( m_pSong == NULL ) { + m_audioEngineState = STATE_PREPARED; + } else { + m_audioEngineState = STATE_READY; + } + + + if ( m_pSong ) { + m_pAudioDriver->setBpm( m_pSong->__bpm ); + } + + if ( m_audioEngineState == STATE_PREPARED ) { + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_PREPARED ); + } else if ( m_audioEngineState == STATE_READY ) { + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_READY ); + } + + // Unlocking earlier might execute the jack process() callback before we + // are fully initialized. + mx.unlock(); + AudioEngine::get_instance()->unlock(); + + if ( m_pAudioDriver ) { + int res = m_pAudioDriver->connect(); + if ( res != 0 ) { + audioEngine_raiseError( Hydrogen::ERROR_STARTING_DRIVER ); + ___ERRORLOG( "Error starting audio driver [audioDriver::connect()]" ); + ___ERRORLOG( "Using the NULL output audio driver" ); + + mx.relock(); + delete m_pAudioDriver; + m_pAudioDriver = new NullDriver( audioEngine_process ); + mx.unlock(); + m_pAudioDriver->init( 0 ); + m_pAudioDriver->connect(); + } + + if ( ( m_pMainBuffer_L = m_pAudioDriver->getOut_L() ) == NULL ) { + ___ERRORLOG( "m_pMainBuffer_L == NULL" ); + } + if ( ( m_pMainBuffer_R = m_pAudioDriver->getOut_R() ) == NULL ) { + ___ERRORLOG( "m_pMainBuffer_R == NULL" ); + } #ifdef H2CORE_HAVE_JACK - audioEngine_renameJackPorts(); + audioEngine_renameJackPorts(); #endif - audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); - } + audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); + } } @@ -1720,45 +1732,45 @@ /// Stop all audio drivers void audioEngine_stopAudioDrivers() { - ___INFOLOG( "[audioEngine_stopAudioDrivers]" ); + ___INFOLOG( "[audioEngine_stopAudioDrivers]" ); - // check current state - if ( m_audioEngineState == STATE_PLAYING ) { - audioEngine_stop(); - } - - if ( ( m_audioEngineState != STATE_PREPARED ) - && ( m_audioEngineState != STATE_READY ) ) { - ___ERRORLOG( QString( "Error: the audio engine is not in PREPARED" + // check current state + if ( m_audioEngineState == STATE_PLAYING ) { + audioEngine_stop(); + } + + if ( ( m_audioEngineState != STATE_PREPARED ) + && ( m_audioEngineState != STATE_READY ) ) { + ___ERRORLOG( QString( "Error: the audio engine is not in PREPARED" " or READY state. state=%1" ) .arg( m_audioEngineState ) ); - return; - } + return; + } - // change the current audio engine state - m_audioEngineState = STATE_INITIALIZED; - EventQueue::get_instance()->push_event( EVENT_STATE, STATE_INITIALIZED ); - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - // delete MIDI driver - if ( m_pMidiDriver ) { - m_pMidiDriver->close(); - delete m_pMidiDriver; - m_pMidiDriver = NULL; - m_pMidiDriverOut = NULL; - } - - // delete audio driver - if ( m_pAudioDriver ) { - m_pAudioDriver->disconnect(); - QMutexLocker mx( &mutex_OutputPointer ); - delete m_pAudioDriver; - m_pAudioDriver = NULL; - mx.unlock(); - } + // change the current audio engine state + m_audioEngineState = STATE_INITIALIZED; + EventQueue::get_instance()->push_event( EVENT_STATE, STATE_INITIALIZED ); + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + // delete MIDI driver + if ( m_pMidiDriver ) { + m_pMidiDriver->close(); + delete m_pMidiDriver; + m_pMidiDriver = NULL; + m_pMidiDriverOut = NULL; + } + + // delete audio driver + if ( m_pAudioDriver ) { + m_pAudioDriver->disconnect(); + QMutexLocker mx( &mutex_OutputPointer ); + delete m_pAudioDriver; + m_pAudioDriver = NULL; + mx.unlock(); + } - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); } @@ -1766,8 +1778,8 @@ /// Restart all audio and midi drivers void audioEngine_restartAudioDrivers() { - audioEngine_stopAudioDrivers(); - audioEngine_startAudioDrivers(); + audioEngine_stopAudioDrivers(); + audioEngine_startAudioDrivers(); } @@ -1786,24 +1798,24 @@ const char* Hydrogen::__class_name = "Hydrogen"; Hydrogen::Hydrogen() - : Object( __class_name ) + : Object( __class_name ) { - if ( __instance ) { - ERRORLOG( "Hydrogen audio engine is already running" ); - throw H2Exception( "Hydrogen audio engine is already running" ); - } - - INFOLOG( "[Hydrogen]" ); - - hydrogenInstance = this; -// __instance = this; - audioEngine_init(); - // Prevent double creation caused by calls from MIDI thread - __instance = this; - audioEngine_startAudioDrivers(); - for(int i = 0; i<128; i++){ - m_nInstrumentLookupTable[i] = i; - } + if ( __instance ) { + ERRORLOG( "Hydrogen audio engine is already running" ); + throw H2Exception( "Hydrogen audio engine is already running" ); + } + + INFOLOG( "[Hydrogen]" ); + + hydrogenInstance = this; + // __instance = this; + audioEngine_init(); + // Prevent double creation caused by calls from MIDI thread + __instance = this; + audioEngine_startAudioDrivers(); + for(int i = 0; i<128; i++){ + m_nInstrumentLookupTable[i] = i; + } } @@ -1811,44 +1823,44 @@ Hydrogen::~Hydrogen() { - INFOLOG( "[~Hydrogen]" ); - if ( m_audioEngineState == STATE_PLAYING ) { - audioEngine_stop(); - } - removeSong(); - audioEngine_stopAudioDrivers(); - audioEngine_destroy(); - __kill_instruments(); - __instance = NULL; + INFOLOG( "[~Hydrogen]" ); + if ( m_audioEngineState == STATE_PLAYING ) { + audioEngine_stop(); + } + removeSong(); + audioEngine_stopAudioDrivers(); + audioEngine_destroy(); + __kill_instruments(); + __instance = NULL; } void Hydrogen::create_instance() { - // Create all the other instances that we need - // ....and in the right order - Logger::create_instance(); - MidiMap::create_instance(); - Preferences::create_instance(); - EventQueue::create_instance(); - MidiActionManager::create_instance(); - - if( __instance == 0 ) { - __instance = new Hydrogen; - } - - // See audioEngine_init() for: - // AudioEngine::create_instance(); - // Effects::create_instance(); - // Playlist::create_instance(); + // Create all the other instances that we need + // ....and in the right order + Logger::create_instance(); + MidiMap::create_instance(); + Preferences::create_instance(); + EventQueue::create_instance(); + MidiActionManager::create_instance(); + + if( __instance == 0 ) { + __instance = new Hydrogen; + } + + // See audioEngine_init() for: + // AudioEngine::create_instance(); + // Effects::create_instance(); + // Playlist::create_instance(); } /// Start the internal sequencer void Hydrogen::sequencer_play() { - getSong()->get_pattern_list()->set_to_old(); - m_pAudioDriver->play(); + getSong()->get_pattern_list()->set_to_old(); + m_pAudioDriver->play(); } @@ -1856,40 +1868,40 @@ /// Stop the internal sequencer void Hydrogen::sequencer_stop() { - if( Hydrogen::get_instance()->getMidiOutput() != NULL ){ - Hydrogen::get_instance()->getMidiOutput()->handleQueueAllNoteOff(); - } + if( Hydrogen::get_instance()->getMidiOutput() != NULL ){ + Hydrogen::get_instance()->getMidiOutput()->handleQueueAllNoteOff(); + } - m_pAudioDriver->stop(); - Preferences::get_instance()->setRecordEvents(false); + m_pAudioDriver->stop(); + Preferences::get_instance()->setRecordEvents(false); } void Hydrogen::setSong( Song *pSong ) { - audioEngine_setSong( pSong ); + audioEngine_setSong( pSong ); } void Hydrogen::removeSong() { - audioEngine_removeSong(); + audioEngine_removeSong(); } Song* Hydrogen::getSong() { - return m_pSong; + return m_pSong; } void Hydrogen::midi_noteOn( Note *note ) { - audioEngine_noteOn( note ); + audioEngine_noteOn( note ); } @@ -1903,551 +1915,599 @@ bool forcePlay, int msg1 ) { - UNUSED( pitch ); + UNUSED( pitch ); - Preferences *pref = Preferences::get_instance(); - unsigned int realcolumn = 0; - unsigned res = pref->getPatternEditorGridResolution(); - int nBase = pref->isPatternEditorUsingTriplets() ? 3 : 4; - int scalar = ( 4 * MAX_NOTES ) / ( res * nBase ); - bool hearnote = forcePlay; - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - - Song *song = getSong(); - if ( !pref->__playselectedinstrument ){ - if ( instrument >= ( int )song->get_instrument_list()->size() ) { - // unused instrument - AudioEngine::get_instance()->unlock(); - return; - } - } - - // Get current partern and column, compensating for "lookahead" if required - Pattern* currentPattern = NULL; - unsigned int column = 0; - unsigned int lookaheadTicks = m_nLookaheadFrames / m_pAudioDriver->m_transport.m_nTickSize; - bool doRecord = pref->getRecordEvents(); - if ( m_pSong->get_mode() == Song::SONG_MODE && doRecord && - m_audioEngineState == STATE_PLAYING ) { - - // Recording + song playback mode + actually playing - PatternList *pPatternList = m_pSong->get_pattern_list(); - int ipattern = getPatternPos(); // playlist index - if ( ipattern < 0 || ipattern >= (int) pPatternList->size() ) { - AudioEngine::get_instance()->unlock(); // unlock the audio engine - return; - } - // Locate column -- may need to jump back in the pattern list - column = getTickPosition(); - while ( column < lookaheadTicks ) { - ipattern -= 1; - if ( ipattern < 0 || ipattern >= (int) pPatternList->size() ) { - AudioEngine::get_instance()->unlock(); // unlock the audio engine - return; - } - // Convert from playlist index to actual pattern index - std::vector *pColumns = m_pSong->get_pattern_group_vector(); - for ( int i = 0; i <= ipattern; ++i ) { - PatternList *pColumn = ( *pColumns )[i]; - currentPattern = pColumn->get( 0 ); - } - column = column + currentPattern->get_length(); -// WARNINGLOG( "Undoing lookahead: corrected (" + to_string( ipattern+1 ) + -// "," + to_string( (int) ( column - currentPattern->get_length() ) - -// (int) lookaheadTicks ) + ") -> (" + to_string(ipattern) + -// "," + to_string( (int) column - (int) lookaheadTicks ) + ")." ); - } - column -= lookaheadTicks; - // Convert from playlist index to actual pattern index (if not already done above) - if ( currentPattern == NULL ) { - std::vector *pColumns = m_pSong->get_pattern_group_vector(); - for ( int i = 0; i <= ipattern; ++i ) { - PatternList *pColumn = ( *pColumns )[i]; - currentPattern = pColumn->get( 0 ); - } - } - - // Cancel recording if punch area disagrees - doRecord = pref->inPunchArea( ipattern ); - - } else { - - // Not song-record mode - PatternList *pPatternList = m_pSong->get_pattern_list(); - if ( ( m_nSelectedPatternNumber != -1 ) - && ( m_nSelectedPatternNumber < ( int )pPatternList->size() ) ) { - currentPattern = pPatternList->get( m_nSelectedPatternNumber ); - } - if( currentPattern == NULL ){ - AudioEngine::get_instance()->unlock(); // unlock the audio engine - return; - } - // Locate column -- may need to wrap around end of pattern - column = getTickPosition(); - if ( column >= lookaheadTicks ) { - column -= lookaheadTicks; - } else { - lookaheadTicks %= currentPattern->get_length(); - column = (column + currentPattern->get_length() - lookaheadTicks) - % currentPattern->get_length(); - } - - } - - realcolumn = getRealtimeTickPosition(); - - if ( pref->getQuantizeEvents() ) { - // quantize it to scale - unsigned qcolumn = ( unsigned )::round( column / ( double )scalar ) * scalar; - - //we have to make sure that no beat is added on the last displayed note in a bar - //for example: if the pattern has 4 beats, the editor displays 5 beats, so we should avoid adding beats an note 5. - if ( qcolumn == currentPattern->get_length() ) qcolumn = 0; - column = qcolumn; - } - - - unsigned position = column; - m_naddrealtimenotetickposition = column; - - - Instrument *instrRef = 0; - if ( song ) { - instrRef = song->get_instrument_list()->get( m_nInstrumentLookupTable[ instrument ] );//getlookuptable index = instrument+36, ziel wert = der entprechende wert -36 - } - - if ( currentPattern && ( getState() == STATE_PLAYING ) ) { - - if( doRecord && pref->getDestructiveRecord() && pref->m_nRecPreDelete>0 ) { - // Delete notes around current note if option toggled - - int postdelete = 0; - int predelete = 0; - int prefpredelete = pref->m_nRecPreDelete-1; - int prefpostdelete = pref->m_nRecPostDelete; - int length = currentPattern->get_length(); - bool fp = false; - postdelete = column; - - switch (prefpredelete) { - case 0: predelete = length ; postdelete = 0; fp = true; break; - case 1: predelete = length ; fp = true; break; - case 2: predelete = length / 2; fp = true; break; - case 3: predelete = length / 4; fp = true; break; - case 4: predelete = length / 8; fp = true; break; - case 5: predelete = length / 16; fp = true; break; - case 6: predelete = length / 32; fp = true; break; - case 7: predelete = length / 64; fp = true; break; - case 8: predelete = length / 64; break; - case 9: predelete = length / 32; break; - case 10: predelete = length / 16; break; - case 11: predelete = length / 8; break; - case 12: predelete = length / 4; break; - case 13: predelete = length / 2; break; - case 14: predelete = length; break; - case 15: break; - default : predelete = 1; break; - } - - if(!fp ){ - switch (prefpostdelete) { - case 0: postdelete = column; break; - case 1: postdelete -= length / 64; break; - case 2: postdelete -= length / 32; break; - case 3: postdelete -= length / 16; break; - case 4: postdelete -= length / 8; break; - case 5: postdelete -= length / 4; break; - case 6: postdelete -= length / 2; break; - case 7: postdelete -= length ; break; - default : postdelete = column; break; - } - if (postdelete<0) postdelete = 0; - - } - - Pattern::notes_t* notes = (Pattern::notes_t*)currentPattern->get_notes(); - FOREACH_NOTE_IT_BEGIN_END(notes,it) { - Note *pNote = it->second; - assert( pNote ); - - if( pref->__playselectedinstrument ){//fix me - if( song->get_instrument_list()->get( getSelectedInstrumentNumber()) == pNote->get_instrument() ){ - if(prefpredelete>=1 && prefpredelete <=14 ) - pNote->set_just_recorded( false ); - if( (prefpredelete == 15) && (pNote->get_just_recorded() == false)){ - delete pNote; - notes->erase( it ); - continue; - } - if( ( pNote->get_just_recorded() == false ) && (static_cast( pNote->get_position() ) >= postdelete && pNote->get_position() < column + predelete +1 )){ - delete pNote; - notes->erase( it ); - } - } - continue; - } - - if ( !fp && pNote->get_instrument() != instrRef ) { - continue; - } - - if(prefpredelete>=1 && prefpredelete <=14 ) - pNote->set_just_recorded( false ); - - if( (prefpredelete == 15) && (pNote->get_just_recorded() == false)){ - delete pNote; - notes->erase( it ); - continue; - } - - if( ( pNote->get_just_recorded() == false ) && ( static_cast( pNote->get_position() ) >= postdelete && pNote->get_position() erase( it ); - } - - } - } - assert( currentPattern != NULL ); - - bool bNoteAlreadyExist = false; - Note *pNoteOld = NULL; - for ( unsigned nNote = 0 ; - nNote < currentPattern->get_length() ; - nNote++ ) { - const Pattern::notes_t* notes = currentPattern->get_notes(); - FOREACH_NOTE_CST_IT_BOUND(notes,it,nNote) { - pNoteOld = it->second; - if ( pNoteOld!=NULL ) { - if ( pNoteOld->get_instrument() == instrRef - && nNote==column ) { - bNoteAlreadyExist = true; - break; - } - } - } - } - - if ( bNoteAlreadyExist ) { - // in this case, we'll leave the note alone - // hear note only if not playing too - if ( pref->getHearNewNotes() - && getState() == STATE_READY ) { - hearnote = true; - } - // Update velocity and flag as just recorded - if ( doRecord ) { - pNoteOld->set_velocity( velocity ); - pNoteOld->set_just_recorded( true ); - } - } else if ( !doRecord ) { - if ( pref->getHearNewNotes() - && ( getState() == STATE_READY - || getState() == STATE_PLAYING ) ) { - hearnote = true; - } - } else { - if ( !pref->__playselectedinstrument ){ - // create the new note - Note *note = new Note( instrRef, - position, - velocity, - pan_L, - pan_R, - -1, - 0 ); - currentPattern->insert_note( note, column ); - - // hear note if its not in the future - if ( pref->getHearNewNotes() - && position <= getTickPosition() ) { - hearnote = true; - } - - note->set_just_recorded( true ); - song->__is_modified = true; - - EventQueue::get_instance()->push_event( EVENT_PATTERN_MODIFIED, -1 ); - } - else if ( pref->__playselectedinstrument ){ - - Note *note = new Note( song->get_instrument_list()->get( getSelectedInstrumentNumber()), - position, - velocity, - pan_L, - pan_R, - -1, - 0 ); - - int divider = msg1 / 12; - Note::Octave octave = (Note::Octave)(divider -3); - Note::Key notehigh = (Note::Key)(msg1 - (12 * divider)); - note->set_midi_info( notehigh, octave, msg1 ); - - currentPattern->insert_note( note, column ); - - // hear note if its not in the future - if ( pref->getHearNewNotes() - && position <= getTickPosition() ) { - hearnote = true; - } - - note->set_just_recorded( true ); - song->__is_modified = true; - - EventQueue::get_instance()->push_event( EVENT_PATTERN_MODIFIED, -1 ); - } - } - } else if ( pref->getHearNewNotes() ) { - hearnote = true; - } - - if ( !pref->__playselectedinstrument ){ - if ( hearnote && instrRef ) { - Note *note2 = new Note( instrRef, - realcolumn, - velocity, - pan_L, - pan_R, - -1, - 0 ); - midi_noteOn( note2 ); - } - }else - { - if ( hearnote ) { - Note *note2 = new Note( song->get_instrument_list()->get( getSelectedInstrumentNumber()), - realcolumn, - velocity, - pan_L, - pan_R, - -1, - 0 ); - - int divider = msg1 / 12; - Note::Octave octave = (Note::Octave)(divider -3); - Note::Key notehigh = (Note::Key)(msg1 - (12 * divider)); - - //ERRORLOG( QString( "octave: %1, note: %2, instrument %3" ).arg( octave ).arg(notehigh).arg(instrument)); - note2->set_midi_info( notehigh, octave, msg1 ); - midi_noteOn( note2 ); - } + Preferences *pref = Preferences::get_instance(); + unsigned int realcolumn = 0; + unsigned res = pref->getPatternEditorGridResolution(); + int nBase = pref->isPatternEditorUsingTriplets() ? 3 : 4; + int scalar = ( 4 * MAX_NOTES ) / ( res * nBase ); + bool hearnote = forcePlay; + int currentPatternNumber; + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + + Song *song = getSong(); + if ( !pref->__playselectedinstrument ){ + if ( instrument >= ( int )song->get_instrument_list()->size() ) { + // unused instrument + AudioEngine::get_instance()->unlock(); + return; + } + } + + // Get current partern and column, compensating for "lookahead" if required + Pattern* currentPattern = NULL; + unsigned int column = 0; + unsigned int lookaheadTicks = m_nLookaheadFrames / m_pAudioDriver->m_transport.m_nTickSize; + bool doRecord = pref->getRecordEvents(); + if ( m_pSong->get_mode() == Song::SONG_MODE && doRecord && + m_audioEngineState == STATE_PLAYING ) { + + // Recording + song playback mode + actually playing + PatternList *pPatternList = m_pSong->get_pattern_list(); + int ipattern = getPatternPos(); // playlist index + if ( ipattern < 0 || ipattern >= (int) pPatternList->size() ) { + AudioEngine::get_instance()->unlock(); // unlock the audio engine + return; + } + // Locate column -- may need to jump back in the pattern list + column = getTickPosition(); + while ( column < lookaheadTicks ) { + ipattern -= 1; + if ( ipattern < 0 || ipattern >= (int) pPatternList->size() ) { + AudioEngine::get_instance()->unlock(); // unlock the audio engine + return; + } + // Convert from playlist index to actual pattern index + std::vector *pColumns = m_pSong->get_pattern_group_vector(); + for ( int i = 0; i <= ipattern; ++i ) { + PatternList *pColumn = ( *pColumns )[i]; + currentPattern = pColumn->get( 0 ); + currentPatternNumber = i; + } + column = column + currentPattern->get_length(); + // WARNINGLOG( "Undoing lookahead: corrected (" + to_string( ipattern+1 ) + + // "," + to_string( (int) ( column - currentPattern->get_length() ) - + // (int) lookaheadTicks ) + ") -> (" + to_string(ipattern) + + // "," + to_string( (int) column - (int) lookaheadTicks ) + ")." ); + } + column -= lookaheadTicks; + // Convert from playlist index to actual pattern index (if not already done above) + if ( currentPattern == NULL ) { + std::vector *pColumns = m_pSong->get_pattern_group_vector(); + for ( int i = 0; i <= ipattern; ++i ) { + PatternList *pColumn = ( *pColumns )[i]; + currentPattern = pColumn->get( 0 ); + currentPatternNumber = i; + } + } + + // Cancel recording if punch area disagrees + doRecord = pref->inPunchArea( ipattern ); + + } else { + + // Not song-record mode + PatternList *pPatternList = m_pSong->get_pattern_list(); + if ( ( m_nSelectedPatternNumber != -1 ) + && ( m_nSelectedPatternNumber < ( int )pPatternList->size() ) ) { + currentPattern = pPatternList->get( m_nSelectedPatternNumber ); + currentPatternNumber = m_nSelectedPatternNumber; + } + if( currentPattern == NULL ){ + AudioEngine::get_instance()->unlock(); // unlock the audio engine + return; + } + // Locate column -- may need to wrap around end of pattern + column = getTickPosition(); + if ( column >= lookaheadTicks ) { + column -= lookaheadTicks; + } else { + lookaheadTicks %= currentPattern->get_length(); + column = (column + currentPattern->get_length() - lookaheadTicks) + % currentPattern->get_length(); + } + + } + + realcolumn = getRealtimeTickPosition(); + + if ( pref->getQuantizeEvents() ) { + // quantize it to scale + unsigned qcolumn = ( unsigned )::round( column / ( double )scalar ) * scalar; + + //we have to make sure that no beat is added on the last displayed note in a bar + //for example: if the pattern has 4 beats, the editor displays 5 beats, so we should avoid adding beats an note 5. + if ( qcolumn == currentPattern->get_length() ) qcolumn = 0; + column = qcolumn; + } + + + unsigned position = column; + m_naddrealtimenotetickposition = column; + + + Instrument *instrRef = 0; + if ( song ) { + instrRef = song->get_instrument_list()->get( m_nInstrumentLookupTable[ instrument ] );//getlookuptable index = instrument+36, ziel wert = der entprechende wert -36 + } + + if ( currentPattern && ( getState() == STATE_PLAYING ) ) { + + if( doRecord && pref->getDestructiveRecord() && pref->m_nRecPreDelete>0 ) { + // Delete notes around current note if option toggled + + int postdelete = 0; + int predelete = 0; + int prefpredelete = pref->m_nRecPreDelete-1; + int prefpostdelete = pref->m_nRecPostDelete; + int length = currentPattern->get_length(); + bool fp = false; + postdelete = column; + + switch (prefpredelete) { + case 0: predelete = length ; postdelete = 0; fp = true; break; + case 1: predelete = length ; fp = true; break; + case 2: predelete = length / 2; fp = true; break; + case 3: predelete = length / 4; fp = true; break; + case 4: predelete = length / 8; fp = true; break; + case 5: predelete = length / 16; fp = true; break; + case 6: predelete = length / 32; fp = true; break; + case 7: predelete = length / 64; fp = true; break; + case 8: predelete = length / 64; break; + case 9: predelete = length / 32; break; + case 10: predelete = length / 16; break; + case 11: predelete = length / 8; break; + case 12: predelete = length / 4; break; + case 13: predelete = length / 2; break; + case 14: predelete = length; break; + case 15: break; + default : predelete = 1; break; + } + + if(!fp ){ + switch (prefpostdelete) { + case 0: postdelete = column; break; + case 1: postdelete -= length / 64; break; + case 2: postdelete -= length / 32; break; + case 3: postdelete -= length / 16; break; + case 4: postdelete -= length / 8; break; + case 5: postdelete -= length / 4; break; + case 6: postdelete -= length / 2; break; + case 7: postdelete -= length ; break; + default : postdelete = column; break; + } + if (postdelete<0) postdelete = 0; + + } + + Pattern::notes_t* notes = (Pattern::notes_t*)currentPattern->get_notes(); + FOREACH_NOTE_IT_BEGIN_END(notes,it) { + Note *pNote = it->second; + assert( pNote ); + int currentPosition = pNote->get_position(); + + if( pref->__playselectedinstrument ){//fix me + if( song->get_instrument_list()->get( getSelectedInstrumentNumber()) == pNote->get_instrument() ){ + if(prefpredelete>=1 && prefpredelete <=14 ) + pNote->set_just_recorded( false ); + if( (prefpredelete == 15) && (pNote->get_just_recorded() == false)){ + bool replaceExisting = false; + if(column == currentPosition) + replaceExisting = true; + EventQueue::AddMidiNoteVector noteAction; + noteAction.m_column = currentPosition; + noteAction.m_row = pNote->get_instrument_id();//getSelectedInstrumentNumber(); + noteAction.m_pattern = currentPatternNumber; + noteAction.f_velocity = velocity; + noteAction.f_pan_L = pan_L; + noteAction.f_pan_R = pan_R; + noteAction.m_length = -1; + + int divider = msg1 / 12; + noteAction.no_octaveKeyVal = (Note::Octave)(divider -3); + noteAction.nk_noteKeyVal = (Note::Key)(msg1 - (12 * divider)); + noteAction.b_isInstrumentMode = replaceExisting; + noteAction.b_isMidi = true; + noteAction.b_noteExist = replaceExisting; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + continue; + } + if( ( pNote->get_just_recorded() == false ) && (static_cast( pNote->get_position() ) >= postdelete && pNote->get_position() < column + predelete +1 )){ + bool replaceExisting = false; + if(column == currentPosition) + replaceExisting = true; + EventQueue::AddMidiNoteVector noteAction; + noteAction.m_column = currentPosition; + noteAction.m_row = pNote->get_instrument_id();//getSelectedInstrumentNumber(); + noteAction.m_pattern = currentPatternNumber; + noteAction.f_velocity = velocity; + noteAction.f_pan_L = pan_L; + noteAction.f_pan_R = pan_R; + noteAction.m_length = -1; + + int divider = msg1 / 12; + noteAction.no_octaveKeyVal = (Note::Octave)(divider -3); + noteAction.nk_noteKeyVal = (Note::Key)(msg1 - (12 * divider)); + noteAction.b_isInstrumentMode = replaceExisting; + noteAction.b_isMidi = true; + noteAction.b_noteExist = replaceExisting; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + } + } + continue; + } + + if ( !fp && pNote->get_instrument() != instrRef ) { + continue; + } + + if(prefpredelete>=1 && prefpredelete <=14 ) + pNote->set_just_recorded( false ); + + if( (prefpredelete == 15) && (pNote->get_just_recorded() == false)){ + + bool replaceExisting = false; + if(column == currentPosition) + replaceExisting = true; + EventQueue::AddMidiNoteVector noteAction; + noteAction.m_column = currentPosition; + noteAction.m_row = pNote->get_instrument_id();//m_nInstrumentLookupTable[ instrument ]; + noteAction.m_pattern = currentPatternNumber; + noteAction.f_velocity = velocity; + noteAction.f_pan_L = pan_L; + noteAction.f_pan_R = pan_R; + noteAction.m_length = -1; + noteAction.no_octaveKeyVal = (Note::Octave)0; + noteAction.nk_noteKeyVal = (Note::Key)0; + noteAction.b_isInstrumentMode = false; + noteAction.b_isMidi = false; + noteAction.b_noteExist = replaceExisting; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + continue; + } + + if( ( pNote->get_just_recorded() == false ) && ( static_cast( pNote->get_position() ) >= postdelete && pNote->get_position() get_instrument_id();//m_nInstrumentLookupTable[ instrument ]; + noteAction.m_pattern = currentPatternNumber; + noteAction.f_velocity = velocity; + noteAction.f_pan_L = pan_L; + noteAction.f_pan_R = pan_R; + noteAction.m_length = -1; + noteAction.no_octaveKeyVal = (Note::Octave)0; + noteAction.nk_noteKeyVal = (Note::Key)0; + noteAction.b_isInstrumentMode = false; + noteAction.b_isMidi = false; + noteAction.b_noteExist = replaceExisting; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + } + } + } + assert( currentPattern != NULL ); + if( doRecord ){ + bool bNoteAlreadyExist = false; + Note::Key myKey = (Note::Key)0; + Note::Octave myOctave = (Note::Octave)0; + + if(pref->__playselectedinstrument){ + instrRef = song->get_instrument_list()->get( getSelectedInstrumentNumber() ); + int divider = msg1 / 12; + myKey = (Note::Key)(msg1 - (12 * divider)); + myOctave = (Note::Octave)(divider -3); + } + else + { + instrRef = song->get_instrument_list()->get( m_nInstrumentLookupTable[ instrument ] ); + } + + Note* pNoteold = currentPattern->find_note( column, -1, instrRef, myKey, myOctave ); + if( pNoteold ) { + bNoteAlreadyExist = true; + } + if ( !pref->__playselectedinstrument ){ + + EventQueue::AddMidiNoteVector noteAction; + noteAction.m_column = column; + noteAction.m_row = m_nInstrumentLookupTable[ instrument ]; + noteAction.m_pattern = currentPatternNumber; + noteAction.f_velocity = velocity; + noteAction.f_pan_L = pan_L; + noteAction.f_pan_R = pan_R; + noteAction.m_length = -1; + noteAction.no_octaveKeyVal = (Note::Octave)0; + noteAction.nk_noteKeyVal = (Note::Key)0; + noteAction.b_isInstrumentMode = false; + noteAction.b_isMidi = true; + noteAction.b_noteExist = bNoteAlreadyExist; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + + // hear note if its not in the future + if ( pref->getHearNewNotes() + && position <= getTickPosition() ) { + hearnote = true; + } + } + else if ( pref->__playselectedinstrument ){ + + EventQueue::AddMidiNoteVector noteAction; + noteAction.m_column = column; + noteAction.m_row = getSelectedInstrumentNumber(); + noteAction.m_pattern = currentPatternNumber; + noteAction.f_velocity = velocity; + noteAction.f_pan_L = pan_L; + noteAction.f_pan_R = pan_R; + noteAction.m_length = -1; + + int divider = msg1 / 12; + noteAction.no_octaveKeyVal = (Note::Octave)(divider -3); + noteAction.nk_noteKeyVal = (Note::Key)(msg1 - (12 * divider)); + noteAction.b_isInstrumentMode = true; + noteAction.b_isMidi = true; + noteAction.b_noteExist = bNoteAlreadyExist; + EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction); + + // hear note if its not in the future + if ( pref->getHearNewNotes() + && position <= getTickPosition() ) { + hearnote = true; + } + } + } + } else if ( pref->getHearNewNotes() ) { + hearnote = true; + } + + if ( !pref->__playselectedinstrument ){ + if ( hearnote && instrRef ) { + Note *note2 = new Note( instrRef, + realcolumn, + velocity, + pan_L, + pan_R, + -1, + 0 ); + midi_noteOn( note2 ); + } + }else + { + if ( hearnote ) { + Note *note2 = new Note( song->get_instrument_list()->get( getSelectedInstrumentNumber()), + realcolumn, + velocity, + pan_L, + pan_R, + -1, + 0 ); + + int divider = msg1 / 12; + Note::Octave octave = (Note::Octave)(divider -3); + Note::Key notehigh = (Note::Key)(msg1 - (12 * divider)); + + //ERRORLOG( QString( "octave: %1, note: %2, instrument %3" ).arg( octave ).arg(notehigh).arg(instrument)); + note2->set_midi_info( notehigh, octave, msg1 ); + midi_noteOn( note2 ); + } - } + } - AudioEngine::get_instance()->unlock(); // unlock the audio engine + AudioEngine::get_instance()->unlock(); // unlock the audio engine } float Hydrogen::getMasterPeak_L() { - return m_fMasterPeak_L; + return m_fMasterPeak_L; } float Hydrogen::getMasterPeak_R() { - return m_fMasterPeak_R; + return m_fMasterPeak_R; } unsigned long Hydrogen::getTickPosition() { - return m_nPatternTickPosition; + return m_nPatternTickPosition; } unsigned long Hydrogen::getRealtimeTickPosition() { - //unsigned long initTick = audioEngine_getTickPosition(); - unsigned int initTick = ( unsigned int )( m_nRealtimeFrames - / m_pAudioDriver->m_transport.m_nTickSize ); - unsigned long retTick; + //unsigned long initTick = audioEngine_getTickPosition(); + unsigned int initTick = ( unsigned int )( m_nRealtimeFrames + / m_pAudioDriver->m_transport.m_nTickSize ); + unsigned long retTick; - struct timeval currtime; - struct timeval deltatime; + struct timeval currtime; + struct timeval deltatime; - double sampleRate = ( double ) m_pAudioDriver->getSampleRate(); - gettimeofday ( &currtime, NULL ); + double sampleRate = ( double ) m_pAudioDriver->getSampleRate(); + gettimeofday ( &currtime, NULL ); - timersub( &currtime, &m_currentTickTime, &deltatime ); + timersub( &currtime, &m_currentTickTime, &deltatime ); - // add a buffers worth for jitter resistance - double deltaSec = - ( double ) deltatime.tv_sec - + ( deltatime.tv_usec / 1000000.0 ) - + ( m_pAudioDriver->getBufferSize() / ( double )sampleRate ); + // add a buffers worth for jitter resistance + double deltaSec = + ( double ) deltatime.tv_sec + + ( deltatime.tv_usec / 1000000.0 ) + + ( m_pAudioDriver->getBufferSize() / ( double )sampleRate ); - retTick = ( unsigned long ) ( ( sampleRate - / ( double ) m_pAudioDriver->m_transport.m_nTickSize ) - * deltaSec ); + retTick = ( unsigned long ) ( ( sampleRate + / ( double ) m_pAudioDriver->m_transport.m_nTickSize ) + * deltaSec ); - retTick = initTick + retTick; + retTick = initTick + retTick; - return retTick; + return retTick; } PatternList* Hydrogen::getCurrentPatternList() { - return m_pPlayingPatterns; + return m_pPlayingPatterns; } PatternList * Hydrogen::getNextPatterns() { - return m_pNextPatterns; + return m_pNextPatterns; } /// Set the next pattern (Pattern mode only) void Hydrogen::sequencer_setNextPattern( int pos, bool appendPattern, bool deletePattern ) { - m_bAppendNextPattern = appendPattern; - m_bDeleteNextPattern = deletePattern; + m_bAppendNextPattern = appendPattern; + m_bDeleteNextPattern = deletePattern; - AudioEngine::get_instance()->lock( RIGHT_HERE ); + AudioEngine::get_instance()->lock( RIGHT_HERE ); - if ( m_pSong && m_pSong->get_mode() == Song::PATTERN_MODE ) { - PatternList *patternList = m_pSong->get_pattern_list(); - Pattern * p = patternList->get( pos ); - if ( ( pos >= 0 ) && ( pos < ( int )patternList->size() ) ) { - // if p is already on the next pattern list, delete it. - if ( m_pNextPatterns->del( p ) == NULL ) { -// WARNINGLOG( "Adding to nextPatterns" ); - m_pNextPatterns->add( p ); - }/* else { + if ( m_pSong && m_pSong->get_mode() == Song::PATTERN_MODE ) { + PatternList *patternList = m_pSong->get_pattern_list(); + Pattern * p = patternList->get( pos ); + if ( ( pos >= 0 ) && ( pos < ( int )patternList->size() ) ) { + // if p is already on the next pattern list, delete it. + if ( m_pNextPatterns->del( p ) == NULL ) { + // WARNINGLOG( "Adding to nextPatterns" ); + m_pNextPatterns->add( p ); + }/* else { // WARNINGLOG( "Removing " + to_string(pos) ); - }*/ - } else { - ERRORLOG( QString( "pos not in patternList range. pos=%1 " - "patternListSize=%2" ) - .arg( pos ) - .arg( patternList->size() ) ); - m_pNextPatterns->clear(); - } - } else { - ERRORLOG( "can't set next pattern in song mode" ); - m_pNextPatterns->clear(); - } + }*/ + } else { + ERRORLOG( QString( "pos not in patternList range. pos=%1 " + "patternListSize=%2" ) + .arg( pos ) + .arg( patternList->size() ) ); + m_pNextPatterns->clear(); + } + } else { + ERRORLOG( "can't set next pattern in song mode" ); + m_pNextPatterns->clear(); + } - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); } int Hydrogen::getPatternPos() { - return m_nSongPos; + return m_nSongPos; } void Hydrogen::restartDrivers() { - audioEngine_restartAudioDrivers(); + audioEngine_restartAudioDrivers(); } - /// Export a song to a wav file, returns the elapsed time in mSec void Hydrogen::startExportSong( const QString& filename, int rate, int depth ) { - if ( getState() == STATE_PLAYING ) { - sequencer_stop(); - } - AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); - Preferences *pPref = Preferences::get_instance(); - - m_oldEngineMode = m_pSong->get_mode(); - m_bOldLoopEnabled = m_pSong->is_loop_enabled(); + if ( getState() == STATE_PLAYING ) { + sequencer_stop(); + } + AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); + Preferences *pPref = Preferences::get_instance(); + + m_oldEngineMode = m_pSong->get_mode(); + m_bOldLoopEnabled = m_pSong->is_loop_enabled(); + + m_pSong->set_mode( Song::SONG_MODE ); + m_pSong->set_loop_enabled( true ); + // unsigned nSamplerate = m_pAudioDriver->getSampleRate(); + unsigned nSamplerate = (unsigned)rate; + // stop all audio drivers + audioEngine_stopAudioDrivers(); - m_pSong->set_mode( Song::SONG_MODE ); - m_pSong->set_loop_enabled( true ); -// unsigned nSamplerate = m_pAudioDriver->getSampleRate(); - unsigned nSamplerate = (unsigned)rate; - // stop all audio drivers - audioEngine_stopAudioDrivers(); + /* + FIXME: Questo codice fa davvero schifo.... + */ - /* - FIXME: Questo codice fa davvero schifo.... - */ + m_pAudioDriver = new DiskWriterDriver( audioEngine_process, nSamplerate, filename, depth); - m_pAudioDriver = new DiskWriterDriver( audioEngine_process, nSamplerate, filename, depth); - - // reset - m_pAudioDriver->m_transport.m_nFrames = 0; // reset total frames - m_pAudioDriver->setBpm( m_pSong->__bpm ); - m_nSongPos = 0; - m_nPatternTickPosition = 0; - m_audioEngineState = STATE_PLAYING; - m_nPatternStartTick = -1; + // reset + m_pAudioDriver->m_transport.m_nFrames = 0; // reset total frames + //m_pAudioDriver->setBpm( m_pSong->__bpm ); + m_nSongPos = 0; + m_nPatternTickPosition = 0; + m_audioEngineState = STATE_PLAYING; + m_nPatternStartTick = -1; - int res = m_pAudioDriver->init( pPref->m_nBufferSize ); - if ( res != 0 ) { - ERRORLOG( "Error starting disk writer driver " - "[DiskWriterDriver::init()]" ); - } + int res = m_pAudioDriver->init( pPref->m_nBufferSize ); + if ( res != 0 ) { + ERRORLOG( "Error starting disk writer driver " + "[DiskWriterDriver::init()]" ); + } - m_pMainBuffer_L = m_pAudioDriver->getOut_L(); - m_pMainBuffer_R = m_pAudioDriver->getOut_R(); + m_pMainBuffer_L = m_pAudioDriver->getOut_L(); + m_pMainBuffer_R = m_pAudioDriver->getOut_R(); - audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); + audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); - audioEngine_seek( 0, false ); + audioEngine_seek( 0, false ); - res = m_pAudioDriver->connect(); - if ( res != 0 ) { - ERRORLOG( "Error starting disk writer driver " - "[DiskWriterDriver::connect()]" ); - } + res = m_pAudioDriver->connect(); + if ( res != 0 ) { + ERRORLOG( "Error starting disk writer driver " + "[DiskWriterDriver::connect()]" ); + } } +void Hydrogen::stopExportSong( bool reconnectOldDriver ) +{ + if ( m_pAudioDriver->class_name() != DiskWriterDriver::class_name() ) { + return; + } + // audioEngine_stopAudioDrivers(); + m_pAudioDriver->disconnect(); -void Hydrogen::stopExportSong() -{ - if ( m_pAudioDriver->class_name() != DiskWriterDriver::class_name() ) { - return; - } + m_audioEngineState = STATE_INITIALIZED; + delete m_pAudioDriver; + m_pAudioDriver = NULL; -// audioEngine_stopAudioDrivers(); - m_pAudioDriver->disconnect(); + m_pMainBuffer_L = NULL; + m_pMainBuffer_R = NULL; - m_audioEngineState = STATE_INITIALIZED; - delete m_pAudioDriver; - m_pAudioDriver = NULL; + m_pSong->set_mode( m_oldEngineMode ); + m_pSong->set_loop_enabled( m_bOldLoopEnabled ); - m_pMainBuffer_L = NULL; - m_pMainBuffer_R = NULL; + m_nSongPos = -1; + m_nPatternTickPosition = 0; - m_pSong->set_mode( m_oldEngineMode ); - m_pSong->set_loop_enabled( m_bOldLoopEnabled ); + if(!reconnectOldDriver) return; - m_nSongPos = -1; - m_nPatternTickPosition = 0; - audioEngine_startAudioDrivers(); + audioEngine_startAudioDrivers(); - if ( m_pAudioDriver ) { - m_pAudioDriver->setBpm( m_pSong->__bpm ); - } else { - ERRORLOG( "m_pAudioDriver = NULL" ); - } + if ( m_pAudioDriver ) { + m_pAudioDriver->setBpm( m_pSong->__bpm ); + } else { + ERRORLOG( "m_pAudioDriver = NULL" ); + } } - /// Used to display audio driver info AudioOutput* Hydrogen::getAudioOutput() { - return m_pAudioDriver; + return m_pAudioDriver; } @@ -2455,152 +2515,152 @@ /// Used to display midi driver info MidiInput* Hydrogen::getMidiInput() { - return m_pMidiDriver; + return m_pMidiDriver; } MidiOutput* Hydrogen::getMidiOutput() { - return m_pMidiDriverOut; + return m_pMidiDriverOut; } void Hydrogen::setMasterPeak_L( float value ) { - m_fMasterPeak_L = value; + m_fMasterPeak_L = value; } void Hydrogen::setMasterPeak_R( float value ) { - m_fMasterPeak_R = value; + m_fMasterPeak_R = value; } int Hydrogen::getState() { - return m_audioEngineState; + return m_audioEngineState; } void Hydrogen::setCurrentPatternList( PatternList *pPatternList ) { - AudioEngine::get_instance()->lock( RIGHT_HERE ); - m_pPlayingPatterns = pPatternList; - EventQueue::get_instance()->push_event( EVENT_PATTERN_CHANGED, -1 ); - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->lock( RIGHT_HERE ); + m_pPlayingPatterns = pPatternList; + EventQueue::get_instance()->push_event( EVENT_PATTERN_CHANGED, -1 ); + AudioEngine::get_instance()->unlock(); } float Hydrogen::getProcessTime() { - return m_fProcessTime; + return m_fProcessTime; } float Hydrogen::getMaxProcessTime() { - return m_fMaxProcessTime; + return m_fMaxProcessTime; } int Hydrogen::loadDrumkit( Drumkit *drumkitInfo ) { - int old_ae_state = m_audioEngineState; - if( m_audioEngineState >= STATE_READY ) { - m_audioEngineState = STATE_PREPARED; - } - - INFOLOG( drumkitInfo->get_name() ); - m_currentDrumkit = drumkitInfo->get_name(); - LocalFileMng fileMng; - QString sDrumkitPath = Filesystem::drumkit_path_search( drumkitInfo->get_name() ); - - - //current instrument list - InstrumentList *songInstrList = m_pSong->get_instrument_list(); - - //new instrument list - InstrumentList *pDrumkitInstrList = drumkitInfo->get_instruments(); - - /* - If the old drumkit is bigger then the new drumkit, - delete all instruments with a bigger pos then - pDrumkitInstrList->size(). Otherwise the instruments - from our old instrumentlist with - pos > pDrumkitInstrList->size() stay in the - new instrumentlist - - wolke: info! - this has moved to the end of this function - because we get lost objects in memory - now: - 1. the new drumkit will loaded - 2. all not used instruments will complete deleted - - old funktion: - while ( pDrumkitInstrList->size() < songInstrList->size() ) - { - songInstrList->del(songInstrList->size() - 1); - } - */ - - //needed for the new delete function - int instrumentDiff = songInstrList->size() - pDrumkitInstrList->size(); - - for ( unsigned nInstr = 0; nInstr < pDrumkitInstrList->size(); ++nInstr ) { - Instrument *pInstr = NULL; - if ( nInstr < songInstrList->size() ) { - //instrument exists already - pInstr = songInstrList->get( nInstr ); - assert( pInstr ); - } else { - pInstr = new Instrument(); - // The instrument isn't playing yet; no need for locking - // :-) - Jakob Lund. AudioEngine::get_instance()->lock( - // "Hydrogen::loadDrumkit" ); - songInstrList->add( pInstr ); - // AudioEngine::get_instance()->unlock(); - } - - Instrument *pNewInstr = pDrumkitInstrList->get( nInstr ); - assert( pNewInstr ); - INFOLOG( QString( "Loading instrument (%1 of %2) [%3]" ) - .arg( nInstr ) - .arg( pDrumkitInstrList->size() ) - .arg( pNewInstr->get_name() ) ); - - // creo i nuovi layer in base al nuovo strumento - // Moved code from here right into the Instrument class - Jakob Lund. - pInstr->load_from( drumkitInfo, pNewInstr ); - } - - -//wolke: new delete funktion - if ( instrumentDiff >=0 ){ - for ( int i = 0; i < instrumentDiff ; i++ ){ - removeInstrument( - m_pSong->get_instrument_list()->size() - 1, - true - ); - } - } - - #ifdef H2CORE_HAVE_JACK - AudioEngine::get_instance()->lock( RIGHT_HERE ); - renameJackPorts(); - AudioEngine::get_instance()->unlock(); - #endif + int old_ae_state = m_audioEngineState; + if( m_audioEngineState >= STATE_READY ) { + m_audioEngineState = STATE_PREPARED; + } + + INFOLOG( drumkitInfo->get_name() ); + m_currentDrumkit = drumkitInfo->get_name(); + LocalFileMng fileMng; + QString sDrumkitPath = Filesystem::drumkit_path_search( drumkitInfo->get_name() ); + + + //current instrument list + InstrumentList *songInstrList = m_pSong->get_instrument_list(); + + //new instrument list + InstrumentList *pDrumkitInstrList = drumkitInfo->get_instruments(); + + /* + If the old drumkit is bigger then the new drumkit, + delete all instruments with a bigger pos then + pDrumkitInstrList->size(). Otherwise the instruments + from our old instrumentlist with + pos > pDrumkitInstrList->size() stay in the + new instrumentlist + + wolke: info! + this has moved to the end of this function + because we get lost objects in memory + now: + 1. the new drumkit will loaded + 2. all not used instruments will complete deleted + + old funktion: + while ( pDrumkitInstrList->size() < songInstrList->size() ) + { + songInstrList->del(songInstrList->size() - 1); + } + */ + + //needed for the new delete function + int instrumentDiff = songInstrList->size() - pDrumkitInstrList->size(); - m_audioEngineState = old_ae_state; + for ( unsigned nInstr = 0; nInstr < pDrumkitInstrList->size(); ++nInstr ) { + Instrument *pInstr = NULL; + if ( nInstr < songInstrList->size() ) { + //instrument exists already + pInstr = songInstrList->get( nInstr ); + assert( pInstr ); + } else { + pInstr = new Instrument(); + // The instrument isn't playing yet; no need for locking + // :-) - Jakob Lund. AudioEngine::get_instance()->lock( + // "Hydrogen::loadDrumkit" ); + songInstrList->add( pInstr ); + // AudioEngine::get_instance()->unlock(); + } + + Instrument *pNewInstr = pDrumkitInstrList->get( nInstr ); + assert( pNewInstr ); + INFOLOG( QString( "Loading instrument (%1 of %2) [%3]" ) + .arg( nInstr ) + .arg( pDrumkitInstrList->size() ) + .arg( pNewInstr->get_name() ) ); + + // creo i nuovi layer in base al nuovo strumento + // Moved code from here right into the Instrument class - Jakob Lund. + pInstr->load_from( drumkitInfo, pNewInstr ); + } + + + //wolke: new delete funktion + if ( instrumentDiff >=0 ){ + for ( int i = 0; i < instrumentDiff ; i++ ){ + removeInstrument( + m_pSong->get_instrument_list()->size() - 1, + true + ); + } + } - return 0; //ok +#ifdef H2CORE_HAVE_JACK + AudioEngine::get_instance()->lock( RIGHT_HERE ); + renameJackPorts(); + AudioEngine::get_instance()->unlock(); +#endif + + m_audioEngineState = old_ae_state; + + return 0; //ok } @@ -2608,89 +2668,89 @@ //Hydrogen::loadDrumkit to delete the instruments by number void Hydrogen::removeInstrument( int instrumentnumber, bool conditional ) { - Instrument *pInstr = m_pSong->get_instrument_list()->get( instrumentnumber ); + Instrument *pInstr = m_pSong->get_instrument_list()->get( instrumentnumber ); - PatternList* pPatternList = getSong()->get_pattern_list(); - - if ( conditional ) { - // new! this check if a pattern has an active note if there is an note - //inside the pattern the intrument would not be deleted - for ( int nPattern = 0 ; - nPattern < (int)pPatternList->size() ; - ++nPattern ) { - if( pPatternList - ->get( nPattern ) - ->references( pInstr ) ) { - return; - } - } - } else { - getSong()->purge_instrument( pInstr ); - } - - Song *pSong = getSong(); - InstrumentList* pList = pSong->get_instrument_list(); - if(pList->size()==1){ - AudioEngine::get_instance()->lock( RIGHT_HERE ); - Instrument* pInstr = pList->get( 0 ); - pInstr->set_name( (QString( "Instrument 1" )) ); - // remove all layers - for ( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) { - InstrumentLayer* pLayer = pInstr->get_layer( nLayer ); - delete pLayer; - pInstr->set_layer( NULL, nLayer ); - } - AudioEngine::get_instance()->unlock(); - EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); - INFOLOG("clear last instrument to empty instrument 1 instead delete the last instrument"); - return; - } - - // if the instrument was the last on the instruments list, select the - // next-last - if ( instrumentnumber - >= (int)getSong()->get_instrument_list()->size() - 1 ) { - Hydrogen::get_instance() - ->setSelectedInstrumentNumber( - std::max(0, instrumentnumber - 1) - ); - } - // delete the instrument from the instruments list - AudioEngine::get_instance()->lock( RIGHT_HERE ); - getSong()->get_instrument_list()->del( instrumentnumber ); - getSong()->__is_modified = true; - AudioEngine::get_instance()->unlock(); - - // At this point the instrument has been removed from both the - // instrument list and every pattern in the song. Hence there's no way - // (NOTE) to play on that instrument, and once all notes have stopped - // playing it will be save to delete. - // the ugly name is just for debugging... - QString xxx_name = QString( "XXX_%1" ) . arg( pInstr->get_name() ); - pInstr->set_name( xxx_name ); - __instrument_death_row.push_back( pInstr ); - __kill_instruments(); // checks if there are still notes. - - // this will force a GUI update. - EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); + PatternList* pPatternList = getSong()->get_pattern_list(); + + if ( conditional ) { + // new! this check if a pattern has an active note if there is an note + //inside the pattern the intrument would not be deleted + for ( int nPattern = 0 ; + nPattern < (int)pPatternList->size() ; + ++nPattern ) { + if( pPatternList + ->get( nPattern ) + ->references( pInstr ) ) { + return; + } + } + } else { + getSong()->purge_instrument( pInstr ); + } + + Song *pSong = getSong(); + InstrumentList* pList = pSong->get_instrument_list(); + if(pList->size()==1){ + AudioEngine::get_instance()->lock( RIGHT_HERE ); + Instrument* pInstr = pList->get( 0 ); + pInstr->set_name( (QString( "Instrument 1" )) ); + // remove all layers + for ( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) { + InstrumentLayer* pLayer = pInstr->get_layer( nLayer ); + delete pLayer; + pInstr->set_layer( NULL, nLayer ); + } + AudioEngine::get_instance()->unlock(); + EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); + INFOLOG("clear last instrument to empty instrument 1 instead delete the last instrument"); + return; + } + + // if the instrument was the last on the instruments list, select the + // next-last + if ( instrumentnumber + >= (int)getSong()->get_instrument_list()->size() - 1 ) { + Hydrogen::get_instance() + ->setSelectedInstrumentNumber( + std::max(0, instrumentnumber - 1) + ); + } + // delete the instrument from the instruments list + AudioEngine::get_instance()->lock( RIGHT_HERE ); + getSong()->get_instrument_list()->del( instrumentnumber ); + getSong()->__is_modified = true; + AudioEngine::get_instance()->unlock(); + + // At this point the instrument has been removed from both the + // instrument list and every pattern in the song. Hence there's no way + // (NOTE) to play on that instrument, and once all notes have stopped + // playing it will be save to delete. + // the ugly name is just for debugging... + QString xxx_name = QString( "XXX_%1" ) . arg( pInstr->get_name() ); + pInstr->set_name( xxx_name ); + __instrument_death_row.push_back( pInstr ); + __kill_instruments(); // checks if there are still notes. + + // this will force a GUI update. + EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); } void Hydrogen::raiseError( unsigned nErrorCode ) { - audioEngine_raiseError( nErrorCode ); + audioEngine_raiseError( nErrorCode ); } unsigned long Hydrogen::getTotalFrames() { - return m_pAudioDriver->m_transport.m_nFrames; + return m_pAudioDriver->m_transport.m_nFrames; } unsigned long Hydrogen::getRealtimeFrames() { - return m_nRealtimeFrames; + return m_nRealtimeFrames; } /** @@ -2701,68 +2761,68 @@ */ long Hydrogen::getTickForPosition( int pos ) { - int nPatternGroups = m_pSong->get_pattern_group_vector()->size(); - if( nPatternGroups == 0 ) return -1; + int nPatternGroups = m_pSong->get_pattern_group_vector()->size(); + if( nPatternGroups == 0 ) return -1; - if ( pos >= nPatternGroups ) { - if ( m_pSong->is_loop_enabled() ) { - pos = pos % nPatternGroups; - } else { - WARNINGLOG( QString( "patternPos > nPatternGroups. pos:" - " %1, nPatternGroups: %2") - .arg( pos ) - .arg( nPatternGroups ) ); - return -1; - } - } - - std::vector *pColumns = m_pSong->get_pattern_group_vector(); - long totalTick = 0; - int nPatternSize; - Pattern *pPattern = NULL; - for ( int i = 0; i < pos; ++i ) { - PatternList *pColumn = ( *pColumns )[ i ]; - // prendo solo il primo. I pattern nel gruppo devono avere la - // stessa lunghezza - pPattern = pColumn->get( 0 ); - if ( pPattern ) { - nPatternSize = pPattern->get_length(); - } else { - nPatternSize = MAX_NOTES; - } - - totalTick += nPatternSize; - } - return totalTick; + if ( pos >= nPatternGroups ) { + if ( m_pSong->is_loop_enabled() ) { + pos = pos % nPatternGroups; + } else { + WARNINGLOG( QString( "patternPos > nPatternGroups. pos:" + " %1, nPatternGroups: %2") + .arg( pos ) + .arg( nPatternGroups ) ); + return -1; + } + } + + std::vector *pColumns = m_pSong->get_pattern_group_vector(); + long totalTick = 0; + int nPatternSize; + Pattern *pPattern = NULL; + for ( int i = 0; i < pos; ++i ) { + PatternList *pColumn = ( *pColumns )[ i ]; + // prendo solo il primo. I pattern nel gruppo devono avere la + // stessa lunghezza + pPattern = pColumn->get( 0 ); + if ( pPattern ) { + nPatternSize = pPattern->get_length(); + } else { + nPatternSize = MAX_NOTES; + } + + totalTick += nPatternSize; + } + return totalTick; } /// Set the position in the song void Hydrogen::setPatternPos( int pos ) { - if ( pos < -1 ) - pos = -1; - AudioEngine::get_instance()->lock( RIGHT_HERE ); - EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 ); - long totalTick = getTickForPosition( pos ); - if ( totalTick < 0 ) { - AudioEngine::get_instance()->unlock(); - return; - } - - if ( getState() != STATE_PLAYING ) { - // find pattern immediately when not playing -// int dummy; -// m_nSongPos = findPatternInTick( totalTick, -// m_pSong->is_loop_enabled(), -// &dummy ); - m_nSongPos = pos; - m_nPatternTickPosition = 0; - } - m_pAudioDriver->locate( - ( int ) ( totalTick * m_pAudioDriver->m_transport.m_nTickSize ) - ); + if ( pos < -1 ) + pos = -1; + AudioEngine::get_instance()->lock( RIGHT_HERE ); + EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 ); + long totalTick = getTickForPosition( pos ); + if ( totalTick < 0 ) { + AudioEngine::get_instance()->unlock(); + return; + } + + if ( getState() != STATE_PLAYING ) { + // find pattern immediately when not playing + // int dummy; + // m_nSongPos = findPatternInTick( totalTick, + // m_pSong->is_loop_enabled(), + // &dummy ); + m_nSongPos = pos; + m_nPatternTickPosition = 0; + } + m_pAudioDriver->locate( + ( int ) ( totalTick * m_pAudioDriver->m_transport.m_nTickSize ) + ); - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); } @@ -2771,11 +2831,11 @@ void Hydrogen::getLadspaFXPeak( int nFX, float *fL, float *fR ) { #ifdef H2CORE_HAVE_LADSPA - ( *fL ) = m_fFXPeak_L[nFX]; - ( *fR ) = m_fFXPeak_R[nFX]; + ( *fL ) = m_fFXPeak_L[nFX]; + ( *fR ) = m_fFXPeak_R[nFX]; #else - ( *fL ) = 0; - ( *fR ) = 0; + ( *fL ) = 0; + ( *fR ) = 0; #endif } @@ -2784,8 +2844,8 @@ void Hydrogen::setLadspaFXPeak( int nFX, float fL, float fR ) { #ifdef H2CORE_HAVE_LADSPA - m_fFXPeak_L[nFX] = fL; - m_fFXPeak_R[nFX] = fR; + m_fFXPeak_L[nFX] = fL; + m_fFXPeak_R[nFX] = fR; #endif } @@ -2793,176 +2853,176 @@ void Hydrogen::onTapTempoAccelEvent() { #ifndef WIN32 - INFOLOG( "tap tempo" ); - static timeval oldTimeVal; + INFOLOG( "tap tempo" ); + static timeval oldTimeVal; - struct timeval now; - gettimeofday(&now, NULL); + struct timeval now; + gettimeofday(&now, NULL); - float fInterval = - (now.tv_sec - oldTimeVal.tv_sec) * 1000.0 - + (now.tv_usec - oldTimeVal.tv_usec) / 1000.0; + float fInterval = + (now.tv_sec - oldTimeVal.tv_sec) * 1000.0 + + (now.tv_usec - oldTimeVal.tv_usec) / 1000.0; - oldTimeVal = now; + oldTimeVal = now; - if ( fInterval < 1000.0 ) { - setTapTempo( fInterval ); - } + if ( fInterval < 1000.0 ) { + setTapTempo( fInterval ); + } #endif } void Hydrogen::setTapTempo( float fInterval ) { -// infoLog( "set tap tempo" ); - static float fOldBpm1 = -1; - static float fOldBpm2 = -1; - static float fOldBpm3 = -1; - static float fOldBpm4 = -1; - static float fOldBpm5 = -1; - static float fOldBpm6 = -1; - static float fOldBpm7 = -1; - static float fOldBpm8 = -1; - - float fBPM = 60000.0 / fInterval; - - if ( fabs( fOldBpm1 - fBPM ) > 20 ) { // troppa differenza, niente media - fOldBpm1 = fBPM; - fOldBpm2 = fBPM; - fOldBpm3 = fBPM; - fOldBpm4 = fBPM; - fOldBpm5 = fBPM; - fOldBpm6 = fBPM; - fOldBpm7 = fBPM; - fOldBpm8 = fBPM; - } - - if ( fOldBpm1 == -1 ) { - fOldBpm1 = fBPM; - fOldBpm2 = fBPM; - fOldBpm3 = fBPM; - fOldBpm4 = fBPM; - fOldBpm5 = fBPM; - fOldBpm6 = fBPM; - fOldBpm7 = fBPM; - fOldBpm8 = fBPM; - } - - fBPM = ( fBPM + fOldBpm1 + fOldBpm2 + fOldBpm3 + fOldBpm4 + fOldBpm5 - + fOldBpm6 + fOldBpm7 + fOldBpm8 ) / 9.0; - - - INFOLOG( QString( "avg BPM = %1" ).arg( fBPM ) ); - fOldBpm8 = fOldBpm7; - fOldBpm7 = fOldBpm6; - fOldBpm6 = fOldBpm5; - fOldBpm5 = fOldBpm4; - fOldBpm4 = fOldBpm3; - fOldBpm3 = fOldBpm2; - fOldBpm2 = fOldBpm1; - fOldBpm1 = fBPM; + // infoLog( "set tap tempo" ); + static float fOldBpm1 = -1; + static float fOldBpm2 = -1; + static float fOldBpm3 = -1; + static float fOldBpm4 = -1; + static float fOldBpm5 = -1; + static float fOldBpm6 = -1; + static float fOldBpm7 = -1; + static float fOldBpm8 = -1; + + float fBPM = 60000.0 / fInterval; + + if ( fabs( fOldBpm1 - fBPM ) > 20 ) { // troppa differenza, niente media + fOldBpm1 = fBPM; + fOldBpm2 = fBPM; + fOldBpm3 = fBPM; + fOldBpm4 = fBPM; + fOldBpm5 = fBPM; + fOldBpm6 = fBPM; + fOldBpm7 = fBPM; + fOldBpm8 = fBPM; + } + + if ( fOldBpm1 == -1 ) { + fOldBpm1 = fBPM; + fOldBpm2 = fBPM; + fOldBpm3 = fBPM; + fOldBpm4 = fBPM; + fOldBpm5 = fBPM; + fOldBpm6 = fBPM; + fOldBpm7 = fBPM; + fOldBpm8 = fBPM; + } + + fBPM = ( fBPM + fOldBpm1 + fOldBpm2 + fOldBpm3 + fOldBpm4 + fOldBpm5 + + fOldBpm6 + fOldBpm7 + fOldBpm8 ) / 9.0; + + + INFOLOG( QString( "avg BPM = %1" ).arg( fBPM ) ); + fOldBpm8 = fOldBpm7; + fOldBpm7 = fOldBpm6; + fOldBpm6 = fOldBpm5; + fOldBpm5 = fOldBpm4; + fOldBpm4 = fOldBpm3; + fOldBpm3 = fOldBpm2; + fOldBpm2 = fOldBpm1; + fOldBpm1 = fBPM; - AudioEngine::get_instance()->lock( RIGHT_HERE ); + AudioEngine::get_instance()->lock( RIGHT_HERE ); -// m_pAudioDriver->setBpm( fBPM ); -// m_pSong->setBpm( fBPM ); + // m_pAudioDriver->setBpm( fBPM ); + // m_pSong->setBpm( fBPM ); - setBPM( fBPM ); + setBPM( fBPM ); - AudioEngine::get_instance()->unlock(); + AudioEngine::get_instance()->unlock(); } // Called with audioEngine in LOCKED state. void Hydrogen::setBPM( float fBPM ) { - if ( m_pAudioDriver && m_pSong ) { - m_pAudioDriver->setBpm( fBPM ); - m_pSong->__bpm = fBPM; - m_nNewBpmJTM = fBPM; -// audioEngine_process_checkBPMChanged(); - } + if ( m_pAudioDriver && m_pSong ) { + m_pAudioDriver->setBpm( fBPM ); + m_pSong->__bpm = fBPM; + m_nNewBpmJTM = fBPM; + // audioEngine_process_checkBPMChanged(); + } } void Hydrogen::restartLadspaFX() { - if ( m_pAudioDriver ) { - AudioEngine::get_instance()->lock( RIGHT_HERE ); - audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); - AudioEngine::get_instance()->unlock(); - } else { - ERRORLOG( "m_pAudioDriver = NULL" ); - } + if ( m_pAudioDriver ) { + AudioEngine::get_instance()->lock( RIGHT_HERE ); + audioEngine_setupLadspaFX( m_pAudioDriver->getBufferSize() ); + AudioEngine::get_instance()->unlock(); + } else { + ERRORLOG( "m_pAudioDriver = NULL" ); + } } int Hydrogen::getSelectedPatternNumber() { - return m_nSelectedPatternNumber; + return m_nSelectedPatternNumber; } void Hydrogen::setSelectedPatternNumberWithoutGuiEvent( int nPat ) { - if ( nPat == m_nSelectedPatternNumber - || ( nPat + 1 > m_pSong->get_pattern_list()->size() ) ) - return; - - if ( Preferences::get_instance()->patternModePlaysSelected() ) { - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - m_nSelectedPatternNumber = nPat; - AudioEngine::get_instance()->unlock(); - } else { - m_nSelectedPatternNumber = nPat; - } + if ( nPat == m_nSelectedPatternNumber + || ( nPat + 1 > m_pSong->get_pattern_list()->size() ) ) + return; + + if ( Preferences::get_instance()->patternModePlaysSelected() ) { + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + m_nSelectedPatternNumber = nPat; + AudioEngine::get_instance()->unlock(); + } else { + m_nSelectedPatternNumber = nPat; + } } void Hydrogen::setSelectedPatternNumber( int nPat ) { - // FIXME: controllare se e' valido.. - if ( nPat == m_nSelectedPatternNumber ) return; - - - if ( Preferences::get_instance()->patternModePlaysSelected() ) { - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - m_nSelectedPatternNumber = nPat; - AudioEngine::get_instance()->unlock(); - } else { - m_nSelectedPatternNumber = nPat; - } + // FIXME: controllare se e' valido.. + if ( nPat == m_nSelectedPatternNumber ) return; + - EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 ); + if ( Preferences::get_instance()->patternModePlaysSelected() ) { + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + m_nSelectedPatternNumber = nPat; + AudioEngine::get_instance()->unlock(); + } else { + m_nSelectedPatternNumber = nPat; + } + + EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 ); } int Hydrogen::getSelectedInstrumentNumber() { - return m_nSelectedInstrumentNumber; + return m_nSelectedInstrumentNumber; } void Hydrogen::setSelectedInstrumentNumber( int nInstrument ) { - if ( m_nSelectedInstrumentNumber == nInstrument ) return; + if ( m_nSelectedInstrumentNumber == nInstrument ) return; - m_nSelectedInstrumentNumber = nInstrument; - EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); + m_nSelectedInstrumentNumber = nInstrument; + EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); } #ifdef H2CORE_HAVE_JACK void Hydrogen::renameJackPorts() { - if( Preferences::get_instance()->m_bJackTrackOuts == true ){ - audioEngine_renameJackPorts(); - } + if( Preferences::get_instance()->m_bJackTrackOuts == true ){ + audioEngine_renameJackPorts(); + } } #endif @@ -2971,161 +3031,161 @@ void Hydrogen::setbeatsToCount( int beatstocount) { - m_nbeatsToCount = beatstocount; + m_nbeatsToCount = beatstocount; } int Hydrogen::getbeatsToCount() { - return m_nbeatsToCount; + return m_nbeatsToCount; } void Hydrogen::setNoteLength( float notelength) { - m_ntaktoMeterCompute = notelength; + m_ntaktoMeterCompute = notelength; } float Hydrogen::getNoteLength() { - return m_ntaktoMeterCompute; + return m_ntaktoMeterCompute; } int Hydrogen::getBcStatus() { - return eventCount; + return eventCount; } void Hydrogen::setBcOffsetAdjust() { - //individual fine tuning for the beatcounter - //to adjust ms_offset from different people and controller - Preferences *pref = Preferences::get_instance(); + //individual fine tuning for the beatcounter + //to adjust ms_offset from different people and controller + Preferences *pref = Preferences::get_instance(); - m_nCoutOffset = pref->m_countOffset; - m_nStartOffset = pref->m_startOffset; + m_nCoutOffset = pref->m_countOffset; + m_nStartOffset = pref->m_startOffset; } void Hydrogen::handleBeatCounter() { - // Get first time value: - if (beatCount == 1) - gettimeofday(¤tTime,NULL); - - eventCount++; - - // Set wlastTime to wcurrentTime to remind the time: - lastTime = currentTime; - - // Get new time: - gettimeofday(¤tTime,NULL); - - - // Build doubled time difference: - lastBeatTime = (double)( - lastTime.tv_sec - + (double)(lastTime.tv_usec * US_DIVIDER) - + (int)m_nCoutOffset * .0001 - ); - currentBeatTime = (double)( - currentTime.tv_sec - + (double)(currentTime.tv_usec * US_DIVIDER) - ); - beatDiff = beatCount == 1 ? 0 : currentBeatTime - lastBeatTime; - - //if differences are to big reset the beatconter - if( beatDiff > 3.001 * 1/m_ntaktoMeterCompute ){ - eventCount = 1; - beatCount = 1; - return; - } - // Only accept differences big enough - if (beatCount == 1 || beatDiff > .001) { - if (beatCount > 1) - beatDiffs[beatCount - 2] = beatDiff ; - // Compute and reset: - if (beatCount == m_nbeatsToCount){ - // unsigned long currentframe = getRealtimeFrames(); - double beatTotalDiffs = 0; - for(int i = 0; i < (m_nbeatsToCount - 1); i++) - beatTotalDiffs += beatDiffs[i]; - double beatDiffAverage = - beatTotalDiffs - / (beatCount - 1) - * m_ntaktoMeterCompute ; - beatCountBpm = - (float) ((int) (60 / beatDiffAverage * 100)) - / 100; - AudioEngine::get_instance()->lock( RIGHT_HERE ); - if ( beatCountBpm > 500) - beatCountBpm = 500; - setBPM( beatCountBpm ); - AudioEngine::get_instance()->unlock(); - if (Preferences::get_instance()->m_mmcsetplay - == Preferences::SET_PLAY_OFF) { - beatCount = 1; - eventCount = 1; - }else{ - if ( m_audioEngineState != STATE_PLAYING ){ - unsigned bcsamplerate = - m_pAudioDriver->getSampleRate(); - unsigned long rtstartframe = 0; - if ( m_ntaktoMeterCompute <= 1){ - rtstartframe = - bcsamplerate - * beatDiffAverage - * ( 1/ m_ntaktoMeterCompute ); - }else - { - rtstartframe = - bcsamplerate - * beatDiffAverage - / m_ntaktoMeterCompute ; - } - - int sleeptime = - ( (float) rtstartframe - / (float) bcsamplerate - * (int) 1000 ) - + (int)m_nCoutOffset - + (int) m_nStartOffset; + // Get first time value: + if (beatCount == 1) + gettimeofday(¤tTime,NULL); + + eventCount++; + + // Set wlastTime to wcurrentTime to remind the time: + lastTime = currentTime; + + // Get new time: + gettimeofday(¤tTime,NULL); + + + // Build doubled time difference: + lastBeatTime = (double)( + lastTime.tv_sec + + (double)(lastTime.tv_usec * US_DIVIDER) + + (int)m_nCoutOffset * .0001 + ); + currentBeatTime = (double)( + currentTime.tv_sec + + (double)(currentTime.tv_usec * US_DIVIDER) + ); + beatDiff = beatCount == 1 ? 0 : currentBeatTime - lastBeatTime; + + //if differences are to big reset the beatconter + if( beatDiff > 3.001 * 1/m_ntaktoMeterCompute ){ + eventCount = 1; + beatCount = 1; + return; + } + // Only accept differences big enough + if (beatCount == 1 || beatDiff > .001) { + if (beatCount > 1) + beatDiffs[beatCount - 2] = beatDiff ; + // Compute and reset: + if (beatCount == m_nbeatsToCount){ + // unsigned long currentframe = getRealtimeFrames(); + double beatTotalDiffs = 0; + for(int i = 0; i < (m_nbeatsToCount - 1); i++) + beatTotalDiffs += beatDiffs[i]; + double beatDiffAverage = + beatTotalDiffs + / (beatCount - 1) + * m_ntaktoMeterCompute ; + beatCountBpm = + (float) ((int) (60 / beatDiffAverage * 100)) + / 100; + AudioEngine::get_instance()->lock( RIGHT_HERE ); + if ( beatCountBpm > 500) + beatCountBpm = 500; + setBPM( beatCountBpm ); + AudioEngine::get_instance()->unlock(); + if (Preferences::get_instance()->m_mmcsetplay + == Preferences::SET_PLAY_OFF) { + beatCount = 1; + eventCount = 1; + }else{ + if ( m_audioEngineState != STATE_PLAYING ){ + unsigned bcsamplerate = + m_pAudioDriver->getSampleRate(); + unsigned long rtstartframe = 0; + if ( m_ntaktoMeterCompute <= 1){ + rtstartframe = + bcsamplerate + * beatDiffAverage + * ( 1/ m_ntaktoMeterCompute ); + }else + { + rtstartframe = + bcsamplerate + * beatDiffAverage + / m_ntaktoMeterCompute ; + } + + int sleeptime = + ( (float) rtstartframe + / (float) bcsamplerate + * (int) 1000 ) + + (int)m_nCoutOffset + + (int) m_nStartOffset; #ifdef WIN32 - Sleep( sleeptime ); + Sleep( sleeptime ); #else - usleep( 1000 * sleeptime ); + usleep( 1000 * sleeptime ); #endif - sequencer_play(); - } + sequencer_play(); + } - beatCount = 1; - eventCount = 1; - return; - } - } - else { - beatCount ++; - } - } - return; + beatCount = 1; + eventCount = 1; + return; + } + } + else { + beatCount ++; + } + } + return; } //~ beatcounter // jack transport master unsigned long Hydrogen::getHumantimeFrames() { - return m_nHumantimeFrames; + return m_nHumantimeFrames; } void Hydrogen::setHumantimeFrames(unsigned long hframes) { - m_nHumantimeFrames = hframes; + m_nHumantimeFrames = hframes; } @@ -3133,105 +3193,105 @@ #ifdef H2CORE_HAVE_JACK void Hydrogen::offJackMaster() { - if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { - static_cast< JackOutput* >( m_pAudioDriver )->com_release(); - } + if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { + static_cast< JackOutput* >( m_pAudioDriver )->com_release(); + } } void Hydrogen::onJackMaster() { - if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { - static_cast< JackOutput* >( m_pAudioDriver )->initTimeMaster(); - } + if ( m_pAudioDriver->class_name() == JackOutput::class_name() ) { + static_cast< JackOutput* >( m_pAudioDriver )->initTimeMaster(); + } } unsigned long Hydrogen::getTimeMasterFrames() { - float allframes = 0 ; + float allframes = 0 ; - if ( m_pAudioDriver->m_transport.m_status == TransportInfo::STOPPED ){ + if ( m_pAudioDriver->m_transport.m_status == TransportInfo::STOPPED ){ - int oldtick = getTickPosition(); - for (int i = 0; i <= getPatternPos(); i++){ - float framesforposition = - (long)getTickForHumanPosition(i) - * (float)m_pAudioDriver->m_transport.m_nTickSize; - allframes = framesforposition + allframes; - } - unsigned long framesfortimemaster = (unsigned int)( - allframes - + oldtick * (float)m_pAudioDriver->m_transport.m_nTickSize - ); - m_nHumantimeFrames = framesfortimemaster; - return framesfortimemaster; - }else - { - return m_nHumantimeFrames; - } + int oldtick = getTickPosition(); + for (int i = 0; i <= getPatternPos(); i++){ + float framesforposition = + (long)getTickForHumanPosition(i) + * (float)m_pAudioDriver->m_transport.m_nTickSize; + allframes = framesforposition + allframes; + } + unsigned long framesfortimemaster = (unsigned int)( + allframes + + oldtick * (float)m_pAudioDriver->m_transport.m_nTickSize + ); + m_nHumantimeFrames = framesfortimemaster; + return framesfortimemaster; + }else + { + return m_nHumantimeFrames; + } } #endif long Hydrogen::getTickForHumanPosition( int humanpos ) { - std::vector< PatternList* > * columns = m_pSong->get_pattern_group_vector(); - - int nPatternGroups = columns->size(); - if ( humanpos >= nPatternGroups ) { - if ( m_pSong->is_loop_enabled() ) { - humanpos = humanpos % nPatternGroups; - } else { - return -1; - } - } - -// std::vector *pColumns = -// m_pSong->get_pattern_group_vector()[ humanpos - 1 ] -// .get( 0 )->get_length(); - -// ERRORLOG( "Kick me!" ); - if ( humanpos == 0 ) return 0; - Pattern *pPattern = columns->at( humanpos - 1 )->get( 0 ); - if ( pPattern ) { - return pPattern->get_length(); - } else { - return MAX_NOTES; - } -// int nPatternSize; - -// pColumns - -/* Pattern *pPattern = NULL; - for ( int i = 0; i < humanpos; ++i ) { - PatternList *pColumn = ( *pColumns )[ i ]; - pPattern = pColumn->get( 0 ); - if ( pPattern ) { - nPatternSize = pPattern->get_length(); - } else { - nPatternSize = MAX_NOTES; - } - - humanTick = nPatternSize; - }*/ -// return humanTick; + std::vector< PatternList* > * columns = m_pSong->get_pattern_group_vector(); + + int nPatternGroups = columns->size(); + if ( humanpos >= nPatternGroups ) { + if ( m_pSong->is_loop_enabled() ) { + humanpos = humanpos % nPatternGroups; + } else { + return -1; + } + } + + // std::vector *pColumns = + // m_pSong->get_pattern_group_vector()[ humanpos - 1 ] + // .get( 0 )->get_length(); + + // ERRORLOG( "Kick me!" ); + if ( humanpos == 0 ) return 0; + Pattern *pPattern = columns->at( humanpos - 1 )->get( 0 ); + if ( pPattern ) { + return pPattern->get_length(); + } else { + return MAX_NOTES; + } + // int nPatternSize; + + // pColumns + + /* Pattern *pPattern = NULL; + for ( int i = 0; i < humanpos; ++i ) { + PatternList *pColumn = ( *pColumns )[ i ]; + pPattern = pColumn->get( 0 ); + if ( pPattern ) { + nPatternSize = pPattern->get_length(); + } else { + nPatternSize = MAX_NOTES; + } + + humanTick = nPatternSize; + }*/ + // return humanTick; } float Hydrogen::getNewBpmJTM() { - return m_nNewBpmJTM; + return m_nNewBpmJTM; } void Hydrogen::setNewBpmJTM( float bpmJTM ) { - m_nNewBpmJTM = bpmJTM; + m_nNewBpmJTM = bpmJTM; } void Hydrogen::ComputeHumantimeFrames(uint32_t nFrames) { - if ( ( m_audioEngineState == STATE_PLAYING ) ) - m_nHumantimeFrames = nFrames + m_nHumantimeFrames; + if ( ( m_audioEngineState == STATE_PLAYING ) ) + m_nHumantimeFrames = nFrames + m_nHumantimeFrames; } @@ -3239,106 +3299,106 @@ void Hydrogen::triggerRelocateDuringPlay() { - if ( m_pSong->get_mode() == Song::PATTERN_MODE ) - m_nPatternStartTick = -1; // This forces the barline position + if ( m_pSong->get_mode() == Song::PATTERN_MODE ) + m_nPatternStartTick = -1; // This forces the barline position } void Hydrogen::togglePlaysSelected() { - if ( getSong()->get_mode() != Song::PATTERN_MODE ) - return; - Preferences * P = Preferences::get_instance(); - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - bool isPlaysSelected = P->patternModePlaysSelected(); - - if (isPlaysSelected) - { - m_pPlayingPatterns->clear(); - Pattern * pSelectedPattern = - m_pSong - ->get_pattern_list() - ->get(m_nSelectedPatternNumber); - m_pPlayingPatterns->add( pSelectedPattern ); - } - - P->setPatternModePlaysSelected( !isPlaysSelected ); - - AudioEngine::get_instance()->unlock(); - + if ( getSong()->get_mode() != Song::PATTERN_MODE ) + return; + Preferences * P = Preferences::get_instance(); + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + bool isPlaysSelected = P->patternModePlaysSelected(); + + if (isPlaysSelected) + { + m_pPlayingPatterns->clear(); + Pattern * pSelectedPattern = + m_pSong + ->get_pattern_list() + ->get(m_nSelectedPatternNumber); + m_pPlayingPatterns->add( pSelectedPattern ); + } + + P->setPatternModePlaysSelected( !isPlaysSelected ); + + AudioEngine::get_instance()->unlock(); + } void Hydrogen::__kill_instruments() { - int c = 0; - Instrument * pInstr = NULL; - while ( __instrument_death_row.size() - && __instrument_death_row.front()->is_queued() == 0 ) { - pInstr = __instrument_death_row.front(); - __instrument_death_row.pop_front(); - INFOLOG( QString( "Deleting unused instrument (%1). " - "%2 unused remain." ) - . arg( pInstr->get_name() ) - . arg( __instrument_death_row.size() ) ); - delete pInstr; - c++; - } - if ( __instrument_death_row.size() ) { - pInstr = __instrument_death_row.front(); - INFOLOG( QString( "Instrument %1 still has %2 active notes. " - "Delaying 'delete instrument' operation." ) - . arg( pInstr->get_name() ) - . arg( pInstr->is_queued() ) ); - } + int c = 0; + Instrument * pInstr = NULL; + while ( __instrument_death_row.size() + && __instrument_death_row.front()->is_queued() == 0 ) { + pInstr = __instrument_death_row.front(); + __instrument_death_row.pop_front(); + INFOLOG( QString( "Deleting unused instrument (%1). " + "%2 unused remain." ) + . arg( pInstr->get_name() ) + . arg( __instrument_death_row.size() ) ); + delete pInstr; + c++; + } + if ( __instrument_death_row.size() ) { + pInstr = __instrument_death_row.front(); + INFOLOG( QString( "Instrument %1 still has %2 active notes. " + "Delaying 'delete instrument' operation." ) + . arg( pInstr->get_name() ) + . arg( pInstr->is_queued() ) ); + } } void Hydrogen::__panic() { - sequencer_stop(); - AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); + sequencer_stop(); + AudioEngine::get_instance()->get_sampler()->stop_playing_notes(); } int Hydrogen::__get_selected_PatterNumber() { - return m_nSelectedPatternNumber; + return m_nSelectedPatternNumber; } unsigned int Hydrogen::__getMidiRealtimeNoteTickPosition() { - return m_naddrealtimenotetickposition; + return m_naddrealtimenotetickposition; } void Hydrogen::sortTimelineVector() { - //sort the timeline vector to beats a < b - sort(m_timelinevector.begin(), m_timelinevector.end(), TimelineComparator()); + //sort the timeline vector to beats a < b + sort(m_timelinevector.begin(), m_timelinevector.end(), TimelineComparator()); } void Hydrogen::sortTimelineTagVector() { - //sort the timeline vector to beats a < b - sort(m_timelinetagvector.begin(), m_timelinetagvector.end(), TimelineTagComparator()); + //sort the timeline vector to beats a < b + sort(m_timelinetagvector.begin(), m_timelinetagvector.end(), TimelineTagComparator()); } void Hydrogen::setTimelineBpm() { - //time line test - if ( Preferences::get_instance()->__usetimeline ){ - float bpm = m_pSong->__bpm; - for ( int i = 0; i < static_cast(m_timelinevector.size() ); i++){ - if( m_timelinevector[i].m_htimelinebeat > getPatternPos() ){ - break; - } - bpm = m_timelinevector[i].m_htimelinebpm; - }//for - if(bpm != m_pSong->__bpm){ - setBPM( bpm ); - } - }//if + //time line test + if ( Preferences::get_instance()->getUseTimelineBpm() ){ + float bpm = m_pSong->__bpm; + for ( int i = 0; i < static_cast(m_timelinevector.size() ); i++){ + if( m_timelinevector[i].m_htimelinebeat > getPatternPos() ){ + break; + } + bpm = m_timelinevector[i].m_htimelinebpm; + }//for + if(bpm != m_pSong->__bpm){ + setBPM( bpm ); + } + }//if } }; diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/coremidi_driver.cpp hydrogen-0.9.6~beta2/src/core/src/IO/coremidi_driver.cpp --- hydrogen-0.9.6~beta1/src/core/src/IO/coremidi_driver.cpp 2011-03-17 10:38:22.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/coremidi_driver.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -76,9 +76,14 @@ } else if ( ( nEventType >= 224 ) && ( nEventType < 240 ) ) { // Pitch Wheel Change msg.m_nChannel = nEventType - 224; msg.m_type = MidiMessage::PITCH_WHEEL; - } else if ( ( nEventType >= 240 ) && ( nEventType < 256 ) ) { // System Exclusive - msg.m_nChannel = nEventType - 240; - msg.m_type = MidiMessage::SYSTEM_EXCLUSIVE; + } else if ( ( nEventType >= 240 ) && ( nEventType < 256 ) ) { // System Exclusive + msg.m_type = MidiMessage::SYSEX; + for(int i = 0; i< packet->length;i++){ + msg.m_sysexData.push_back(packet->data[i]); + } + instance->handleMidiMessage( msg ); + packet = MIDIPacketNext( packet ); + return; } else { ___ERRORLOG( QString( "Unhandled midi message type: %1" ).arg( nEventType ) ); ___INFOLOG( "MIDI msg: " ); diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/disk_writer_driver.cpp hydrogen-0.9.6~beta2/src/core/src/IO/disk_writer_driver.cpp --- hydrogen-0.9.6~beta1/src/core/src/IO/disk_writer_driver.cpp 2011-07-08 16:42:02.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/disk_writer_driver.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ +#include #include "DiskWriterDriver.h" #include @@ -37,8 +38,12 @@ void* diskWriterDriver_thread( void* param ) { - Object* __object = ( Object* )param; + + Object* __object = ( Object* )param; DiskWriterDriver *pDriver = ( DiskWriterDriver* )param; + EventQueue::get_instance()->push_event( EVENT_PROGRESS, 0 ); + pDriver->setBpm( Hydrogen::get_instance()->getSong()->__bpm ); + pDriver->audioEngine_process_checkBPMChanged(); __INFOLOG( "DiskWriterDriver thread start" ); // always rolling, no user interaction @@ -130,72 +135,106 @@ float *pData_R = pDriver->m_pOut_R; - //calculate exact song length in frames (no loops). + Hydrogen* engine = Hydrogen::get_instance(); + std::vector *pPatternColumns = Hydrogen::get_instance()->getSong()->get_pattern_group_vector(); int nColumns = pPatternColumns->size(); int nPatternSize; - int nSongSize = 0; - for ( int i = 0; i < nColumns; ++i ) { - PatternList *pColumn = ( *pPatternColumns )[ i ]; + int validBpm = engine->getSong()->__bpm; + float oldBPM = 0; + float ticksize = 0; + for ( int patternposition = 0; patternposition < nColumns; ++patternposition ) { + PatternList *pColumn = ( *pPatternColumns )[ patternposition ]; if ( pColumn->size() != 0 ) { nPatternSize = pColumn->get( 0 )->get_length(); } else { nPatternSize = MAX_NOTES; - } - nSongSize += nPatternSize; - } + } - float ticksize = pDriver->m_nSampleRate * 60.0 / Hydrogen::get_instance()->getSong()->__bpm / 192 *4; - //here we have the song length in frames dependent from bpm and samplerate - unsigned songLengthInFrames = ticksize * nSongSize; - - unsigned frameNumber = 0; - int lastRun = 0; - while ( frameNumber < songLengthInFrames ) { - - int usedBuffer = pDriver->m_nBufferSize; - - //this will calculate the the size from -last- (end of song) used frame buffer, - //which is mostly smaller than pDriver->m_nBufferSize - if( songLengthInFrames - frameNumber < pDriver->m_nBufferSize ){ - lastRun = songLengthInFrames - frameNumber; - usedBuffer = lastRun; - }; - - frameNumber += usedBuffer; - int ret = pDriver->m_processCallback( usedBuffer, NULL ); - - for ( unsigned i = 0; i < usedBuffer; i++ ) { - if(pData_L[i] > 1){ - pData[i * 2] = 1; - } - else if(pData_L[i] < -1){ - pData[i * 2] = -1; - }else - { - pData[i * 2] = pData_L[i]; - } - - if(pData_R[i] > 1){ - pData[i * 2 + 1] = 1; - } - else if(pData_R[i] < -1){ - pData[i * 2 + 1] = -1; - }else - { - pData[i * 2 + 1] = pData_R[i]; - } - } - int res = sf_writef_float( m_file, pData, usedBuffer ); - if ( res != ( int )usedBuffer ) { - __ERRORLOG( "Error during sf_write_float" ); - } - - float fPercent = ( float ) frameNumber / ( float )songLengthInFrames * 100.0; - EventQueue::get_instance()->push_event( EVENT_PROGRESS, ( int )fPercent ); -// frameNuber += lastrun; - } + ticksize = pDriver->m_nSampleRate * 60.0 / engine->getSong()->__bpm / engine->getSong()->__resolution; + // check pattern bpm if timeline bpm is in use + if(Preferences::get_instance()->getUseTimelineBpm() ){ + if( engine->m_timelinevector.size() >= 1 ){ + + for ( int t = 0; t < engine->m_timelinevector.size(); t++){ + if(engine->m_timelinevector[t].m_htimelinebeat == patternposition && engine->m_timelinevector[t].m_htimelinebpm != validBpm){ + validBpm = engine->m_timelinevector[t].m_htimelinebpm; + } + + } + } + pDriver->setBpm(validBpm); + ticksize = pDriver->m_nSampleRate * 60.0 / validBpm / Hydrogen::get_instance()->getSong()->__resolution; + pDriver->audioEngine_process_checkBPMChanged(); + engine->setPatternPos(patternposition); + + // delay needed time to calculate all rubberband samples + if( Preferences::get_instance()->getRubberBandBatchMode() && validBpm != oldBPM ){ + EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); + int sleepTime = Preferences::get_instance()->getRubberBandCalcTime()+1; + while ((sleepTime = sleep(sleepTime)) > 0); + } + oldBPM = validBpm; + + } + else + { + ticksize = pDriver->m_nSampleRate * 60.0 / Hydrogen::get_instance()->getSong()->__bpm / Hydrogen::get_instance()->getSong()->__resolution; + //pDriver->m_transport.m_nTickSize = ticksize; + } + + + //here we have the pattern length in frames dependent from bpm and samplerate + unsigned patternLengthInFrames = ticksize * nPatternSize; + + unsigned frameNumber = 0; + int lastRun = 0; + while ( frameNumber < patternLengthInFrames ) { + + int usedBuffer = pDriver->m_nBufferSize; + + //this will calculate the the size from -last- (end of pattern) used frame buffer, + //which is mostly smaller than pDriver->m_nBufferSize + if( patternLengthInFrames - frameNumber < pDriver->m_nBufferSize ){ + lastRun = patternLengthInFrames - frameNumber; + usedBuffer = lastRun; + }; + + frameNumber += usedBuffer; + int ret = pDriver->m_processCallback( usedBuffer, NULL ); + + for ( unsigned i = 0; i < usedBuffer; i++ ) { + if(pData_L[i] > 1){ + pData[i * 2] = 1; + } + else if(pData_L[i] < -1){ + pData[i * 2] = -1; + }else + { + pData[i * 2] = pData_L[i]; + } + + if(pData_R[i] > 1){ + pData[i * 2 + 1] = 1; + } + else if(pData_R[i] < -1){ + pData[i * 2 + 1] = -1; + }else + { + pData[i * 2 + 1] = pData_R[i]; + } + } + int res = sf_writef_float( m_file, pData, usedBuffer ); + if ( res != ( int )usedBuffer ) { + __ERRORLOG( "Error during sf_write_float" ); + } + } + + // this progress bar methode is not exact but ok enough to give users a usable visible progress feedback + float fPercent = ( float )(patternposition +1) / ( float )nColumns * 100.0; + EventQueue::get_instance()->push_event( EVENT_PROGRESS, ( int )fPercent ); + } delete[] pData; pData = NULL; @@ -206,7 +245,6 @@ pthread_exit( NULL ); -// Hydrogen::get_instance()->stopExportSong(); return NULL; } @@ -259,7 +297,8 @@ pthread_create( &diskWriterDriverThread, &attr, diskWriterDriver_thread, this ); - return 0; + return 0; + } @@ -267,13 +306,13 @@ /// disconnect void DiskWriterDriver::disconnect() { - INFOLOG( "[disconnect]" ); - + INFOLOG( "[disconnect]" ); delete[] m_pOut_L; m_pOut_L = NULL; delete[] m_pOut_R; m_pOut_R = NULL; + } @@ -320,5 +359,31 @@ m_transport.m_nBPM = fBPM; } +void DiskWriterDriver::audioEngine_process_checkBPMChanged() +{ + float fNewTickSize = + getSampleRate() * 60.0 + / Hydrogen::get_instance()->getSong()->__bpm + / Hydrogen::get_instance()->getSong()->__resolution; + + if ( fNewTickSize != m_transport.m_nTickSize ) { + // cerco di convertire ... + float fTickNumber = + ( float )m_transport.m_nFrames + / ( float )m_transport.m_nTickSize; + + m_transport.m_nTickSize = fNewTickSize; + + if ( m_transport.m_nTickSize == 0 ) { + return; + } + + // update frame position + m_transport.m_nFrames = ( long long )( fTickNumber * fNewTickSize ); + + // currently unuseble here + //EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); + } +} }; diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/DiskWriterDriver.h hydrogen-0.9.6~beta2/src/core/src/IO/DiskWriterDriver.h --- hydrogen-0.9.6~beta1/src/core/src/IO/DiskWriterDriver.h 2011-01-06 09:27:15.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/DiskWriterDriver.h 2012-05-25 12:19:45.000000000 +0000 @@ -60,7 +60,9 @@ void disconnect(); void write( float* buffer_L, float* buffer_R, unsigned int bufferSize ); - + + void audioEngine_process_checkBPMChanged(); + unsigned getBufferSize() { return m_nBufferSize; } @@ -81,6 +83,7 @@ private: + }; }; diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/jack_midi_driver.cpp hydrogen-0.9.6~beta2/src/core/src/IO/jack_midi_driver.cpp --- hydrogen-0.9.6~beta1/src/core/src/IO/jack_midi_driver.cpp 2011-07-22 19:32:06.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/jack_midi_driver.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -62,12 +62,12 @@ void JackMidiDriver::JackMidiWrite(jack_nframes_t nframes) { - int error; + int error; int events; int i; void *buf; jack_midi_event_t event; - uint8_t buffer[8]; + uint8_t buffer[13];// 13 is needed if we get sysex goto messages if (input_port == NULL) return; @@ -114,8 +114,8 @@ msg.m_type = MidiMessage::NOTE_ON; msg.m_nData1 = buffer[1]; msg.m_nData2 = buffer[2]; - msg.m_nChannel = buffer[0] & 0xF; - handleMidiMessage(msg); + msg.m_nChannel = buffer[0] & 0xF; + handleMidiMessage(msg); break; case 0xB: /* control change */ msg.m_type = MidiMessage::CONTROL_CHANGE; @@ -131,10 +131,22 @@ msg.m_nChannel = buffer[0] & 0xF; handleMidiMessage(msg); break; - case 0xF: - switch (buffer[0]) { - case 0xF0: /* system exclusive */ - break; + case 0xF: + switch (buffer[0]) { + case 0xF0: /* system exclusive */ + msg.m_type = MidiMessage::SYSEX; + if(buffer[3] == 06 ){// MMC message + for ( int i = 0; i < sizeof(buffer) && i<6; i++ ) { + msg.m_sysexData.push_back( buffer[i] ); + } + }else + { + for ( int i = 0; i < sizeof(buffer); i++ ) { + msg.m_sysexData.push_back( buffer[i] ); + } + } + handleMidiMessage(msg); + break; case 0xF1: msg.m_type = MidiMessage::QUARTER_FRAME; msg.m_nData1 = buffer[1]; @@ -319,8 +331,11 @@ JackMidiDriver::~JackMidiDriver() { if (jack_client != NULL) + { + jack_port_unregister( jack_client, input_port); + jack_port_unregister( jack_client, output_port); jack_deactivate(jack_client); - + } pthread_mutex_destroy(&mtx); } diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/jack_output.cpp hydrogen-0.9.6~beta2/src/core/src/IO/jack_output.cpp --- hydrogen-0.9.6~beta1/src/core/src/IO/jack_output.cpp 2011-11-08 22:10:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/jack_output.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -206,7 +206,7 @@ } } memset( track_output_ports_L, 0, sizeof(track_output_ports_L) ); - memset( track_output_ports_R, 0, sizeof(track_output_ports_R) ); + memset( track_output_ports_R, 0, sizeof(track_output_ports_R) ); } unsigned JackOutput::getBufferSize() @@ -737,22 +737,6 @@ } -void JackOutput::setPortName( int nPort, bool bLeftChannel, const QString& sName ) -{ -// infoLog( "[setPortName] " + sName ); - jack_port_t *pPort; - if ( bLeftChannel ) { - pPort = track_output_ports_L[ nPort ]; - } else { - pPort = track_output_ports_R[ nPort ]; - } - - int err = jack_port_set_name( pPort, sName.toLocal8Bit() ); - if ( err != 0 ) { - ERRORLOG( " Error in jack_port_set_name!" ); - } -} - int JackOutput::getNumTracks() { // INFOLOG( "get num tracks()" ); @@ -774,33 +758,26 @@ enum session_events{ SAVE_SESSION, SAVE_AND_QUIT, - SAVE_TEMPLATE, - SAVE_SESSION_NEW_FILE + SAVE_TEMPLATE }; jack_session_event_t *ev = (jack_session_event_t *) event; /* Valid Song is needed */ if(Hydrogen::get_instance()->getSong()->get_filename().isEmpty()){ - EventQueue::get_instance()->push_event(EVENT_JACK_SESSION, SAVE_SESSION_NEW_FILE); - jack_session_reply(client, ev ); - jack_session_event_free (ev); - return; + Hydrogen::get_instance()->getSong()->set_filename("Untitled_Song"); } - - QString songfilename; - if(Preferences::get_instance()->getJackSessionUseSessionDir()){ - QString jackSessionDirectory = (QString)ev->session_dir; - QStringList list1 = Hydrogen::get_instance()->getSong()->get_filename().split("/"); - QString realFillename = list1[list1.size()-1]; - qDebug()<< realFillename; - Hydrogen::get_instance()->getSong()->set_filename(jackSessionDirectory + realFillename); - songfilename = "\"${SESSION_DIR}\"" + realFillename; - }else - { - songfilename = Hydrogen::get_instance()->getSong()->get_filename(); + if(Hydrogen::get_instance()->getSong()->get_filename().contains(" ")){ + QStringList removeWhiteSpaces = Hydrogen::get_instance()->getSong()->get_filename().split(" "); + Hydrogen::get_instance()->getSong()->set_filename( removeWhiteSpaces.join("_") ); } + QString songfilename; + QString jackSessionDirectory = (QString)ev->session_dir; + QStringList list1 = Hydrogen::get_instance()->getSong()->get_filename().split("/"); + QString realFillename = list1[list1.size()-1]; + Hydrogen::get_instance()->getSong()->set_filename(jackSessionDirectory + realFillename); + songfilename = "\"${SESSION_DIR}\"" + realFillename; QString retval = QString(Preferences::get_instance()->getJackSessionApplicationPath() + " -s" + songfilename + " --jacksessionid " + ev->client_uuid); const char * filename = retval.toAscii().data(); @@ -809,10 +786,8 @@ EventQueue::get_instance()->push_event(EVENT_JACK_SESSION, SAVE_SESSION); } if (ev->type == JackSessionSaveAndQuit) { - if(Preferences::get_instance()->getJackSessionUseSessionDir()){ EventQueue::get_instance()->push_event(EVENT_JACK_SESSION, SAVE_SESSION); - } - EventQueue::get_instance()->push_event(EVENT_JACK_SESSION, SAVE_AND_QUIT); + EventQueue::get_instance()->push_event(EVENT_JACK_SESSION, SAVE_AND_QUIT); } ev->command_line = strdup (filename); diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/midi_input.cpp hydrogen-0.9.6~beta2/src/core/src/IO/midi_input.cpp --- hydrogen-0.9.6~beta1/src/core/src/IO/midi_input.cpp 2011-11-07 22:45:33.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/midi_input.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -306,7 +306,8 @@ 4 Fast Forward 5 Rewind 6 Record strobe (punch in) - 7 Record exit (punch out) + 7 Record exit (punch out) + 8 Record ready 9 Pause @@ -315,7 +316,7 @@ 240 127 id 6 68 6 1 hr mn sc fr ff 247 */ - + MidiActionManager * aH = MidiActionManager::get_instance(); MidiMap * mM = MidiMap::get_instance(); Hydrogen *pEngine = Hydrogen::get_instance(); @@ -323,12 +324,11 @@ pEngine->lastMidiEventParameter = msg.m_nData1; - if ( msg.m_sysexData.size() == 6 ) { if ( - ( msg.m_sysexData[0] == 0xF0 ) && + ( msg.m_sysexData[0] == 240 ) && ( msg.m_sysexData[1] == 127 ) && - ( msg.m_sysexData[2] == 127 ) && + //( msg.m_sysexData[2] == 0 ) && ( msg.m_sysexData[3] == 6 ) ) { @@ -356,8 +356,8 @@ } case 4: // FAST FWD - pEngine->lastMidiEvent = "MMC_FAST_FWD"; - aH->handleAction(mM->getMMCAction("MMC_FAST_FWD")); + pEngine->lastMidiEvent = "MMC_FAST_FORWARD"; + aH->handleAction(mM->getMMCAction("MMC_FAST_FORWARD")); break; @@ -376,6 +376,11 @@ aH->handleAction(mM->getMMCAction("MMC_RECORD_EXIT")); break; + case 8: // RECORD READY + pEngine->lastMidiEvent = "MMC_RECORD_READY"; + aH->handleAction(mM->getMMCAction("MMC_RECORD_READY")); + break; + case 9: //PAUSE pEngine->lastMidiEvent = "MMC_PAUSE"; aH->handleAction(mM->getMMCAction("MMC_PAUSE")); diff -Nru hydrogen-0.9.6~beta1/src/core/src/IO/PortAudioDriver.h hydrogen-0.9.6~beta2/src/core/src/IO/PortAudioDriver.h --- hydrogen-0.9.6~beta1/src/core/src/IO/PortAudioDriver.h 2011-01-06 09:27:15.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/IO/PortAudioDriver.h 2012-05-25 12:19:45.000000000 +0000 @@ -26,6 +26,8 @@ #include #include +#include + #ifdef H2CORE_HAVE_PORTAUDIO #include diff -Nru hydrogen-0.9.6~beta1/src/core/src/local_file_mgr.cpp hydrogen-0.9.6~beta2/src/core/src/local_file_mgr.cpp --- hydrogen-0.9.6~beta1/src/core/src/local_file_mgr.cpp 2011-10-24 14:05:32.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/local_file_mgr.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -256,12 +256,22 @@ //LIB_ID just in work to get better usability //writeXmlString( &rootNode, "LIB_ID", "in_work" ); writeXmlString( rootNode, "pattern_for_drumkit", drumkit_name ); + writeXmlString( rootNode, "author", song->get_author() ); + writeXmlString( rootNode, "license", song->get_license() ); // pattern QDomNode patternNode = doc.createElement( "pattern" ); writeXmlString( patternNode, "pattern_name", realpatternname ); - writeXmlString( patternNode, "category", pat->get_category() ); + + QString category; + if ( pat->get_category().isEmpty() ) + category = "No category"; + else + category = pat->get_category(); + + + writeXmlString( patternNode, "category", category ); writeXmlString( patternNode, "size", QString("%1").arg( pat->get_length() ) ); QDomNode noteListNode = doc.createElement( "noteList" ); @@ -293,21 +303,26 @@ doc.appendChild( rootNode ); + int rv = 0; QFile file( sPatternXmlFilename ); if ( !file.open(QIODevice::WriteOnly) ) - return 0; + rv = 1; QTextStream TextStream( &file ); doc.save( TextStream, 1 ); + + if( file.size() == 0) + rv = 1; + file.close(); QFile anotherTestfile( sPatternXmlFilename ); if ( !anotherTestfile.exists() ) - return 1; + rv = 1; - return 0; // ok + return rv; // ok } @@ -405,7 +420,12 @@ } -std::vector LocalFileMng::getAllPatternName() +/** + * Return the names of all patterns in the soundlibrary. + * \return A vector of QString elements which represent the pattern names. + */ + +std::vector LocalFileMng::getAllPatternNames() { std::vector alllist; @@ -428,7 +448,11 @@ return alllist; } - +/** + * Generate a list of all used categories. This includes only patterns which are located in + * hydrogens soundlibrary. + * \return A vector of QString elements which represent the pattern categories. + */ std::vector LocalFileMng::getAllCategoriesFromPattern() { @@ -438,7 +462,6 @@ std::vector categorylist; for (uint i = 0; i < m_allPatternList.size(); ++i) { QString patternInfoFile = m_allPatternList[i]; - QDomDocument doc = LocalFileMng::openXmlDocument( patternInfoFile ); @@ -450,29 +473,32 @@ QString sCategoryName( LocalFileMng::readXmlString( patternNode,"category", "" ) ); - if ( !sCategoryName.isEmpty() ){ - bool test = true; - for (uint i = 0; i < categorylist.size(); ++i){ - if ( sCategoryName == categorylist[i] ){ - test = false; - } - } - if (test == true){ - categorylist.push_back(sCategoryName); - - //this merge new categories to user categories list - bool test2 = true; - for( cur_testpatternCategories = pPref->m_patternCategories.begin(); cur_testpatternCategories != pPref->m_patternCategories.end(); ++cur_testpatternCategories ){ - if ( sCategoryName == *cur_testpatternCategories ){ - test2 = false; - } - } - - if (test2 == true ) { - pPref->m_patternCategories.push_back( sCategoryName ); - } - } - } + if ( sCategoryName.isEmpty() ){ + sCategoryName = "No category"; + } + + bool test = true; + for (uint i = 0; i < categorylist.size(); ++i){ + if ( sCategoryName == categorylist[i] ){ + test = false; + } + } + if (test == true){ + categorylist.push_back( sCategoryName ); + + //this merge new categories to user categories list + bool test2 = true; + for( cur_testpatternCategories = pPref->m_patternCategories.begin(); cur_testpatternCategories != pPref->m_patternCategories.end(); ++cur_testpatternCategories ){ + if ( sCategoryName == *cur_testpatternCategories ){ + test2 = false; + } + } + + if (test2 == true ) { + pPref->m_patternCategories.push_back( sCategoryName ); + } + } + } } @@ -480,7 +506,11 @@ return categorylist; } - +/** + * Generate a list of all patterns for a given drumkit + * \param sDrumkit the name of drumkit + * \return A vector of QString elements which represent the pattern names. + */ std::vector LocalFileMng::getPatternsForDrumkit( const QString& sDrumkit ) { @@ -508,14 +538,14 @@ return list; } - +/** + * Return a list of drumkits that are located inside a directory. + * \param sDirectory The directory where the method looks for drumkits + * \return A vector of QString elements which represent the drumkits. + */ std::vector LocalFileMng::getDrumkitsFromDirectory( QString sDirectory ) { - /* - returns a list of all drumkits in the given directory - */ - std::vector list; QDir dir( sDirectory ); @@ -540,12 +570,15 @@ } +/** + * Merge two vectors of QStrings. + * \param firstVector The first vector. + * \param secondVector The second vector. + * \return The resulting vector which is a union of firstVector and secondVector. + */ std::vector mergeQStringVectors( std::vector firstVector , std::vector secondVector ) { - /* - merges two vectors ( containing drumkits). Elements of the first vector have priority - */ if( firstVector.size() == 0 ) return secondVector; if( secondVector.size() == 0 ) return firstVector; @@ -575,6 +608,11 @@ } +/** + * Return a list of directories that may contain patterns + * \return A vector of QString elements which represent the directory names. + */ + std::vector LocalFileMng::getPatternDirList() { return getDrumkitsFromDirectory( Preferences::get_instance()->getDataDirectory() + "patterns" ); @@ -587,10 +625,17 @@ return 0; } -int LocalFileMng::savePlayList( const std::string& patternname) + +/** + * Save the currently loaded playlist to disk. + * \param playlist_name The filename of the output file. + * \return Returns an Errorcode. + */ + +int LocalFileMng::savePlayList( const std::string& filename) { - std::string name = patternname.c_str(); + std::string name = filename.c_str(); std::string realname = name.substr(name.rfind("/")+1); @@ -600,18 +645,14 @@ QDomNode rootNode = doc.createElement( "playlist" ); - //LIB_ID just in work to get better usability writeXmlString( rootNode, "Name", QString (realname.c_str()) ); - writeXmlString( rootNode, "LIB_ID", "in_work" ); QDomNode playlistNode = doc.createElement( "Songs" ); for ( uint i = 0; i < Hydrogen::get_instance()->m_PlayList.size(); ++i ){ QDomNode nextNode = doc.createElement( "next" ); LocalFileMng::writeXmlString ( nextNode, "song", Hydrogen::get_instance()->m_PlayList[i].m_hFile ); - LocalFileMng::writeXmlString ( nextNode, "script", Hydrogen::get_instance()->m_PlayList[i].m_hScript ); - LocalFileMng::writeXmlString ( nextNode, "enabled", Hydrogen::get_instance()->m_PlayList[i].m_hScriptEnabled ); playlistNode.appendChild( nextNode ); @@ -620,44 +661,51 @@ rootNode.appendChild( playlistNode ); doc.appendChild( rootNode ); - QString filename = QString( patternname.c_str() ); - QFile file(filename); + int rv = 0; + QFile file( filename.c_str() ); if ( !file.open(QIODevice::WriteOnly) ) - return 0; + rv = 1; QTextStream TextStream( &file ); doc.save( TextStream, 1 ); + if( file.size() == 0) + rv = 1; + file.close(); - return 0; // ok + return rv; // ok } -int LocalFileMng::loadPlayList( const std::string& patternname) +/** + * Load a playlist from disk. + * \param filename The name of the playlist to be saved. + * \return Returns an Errorcode. + */ + +int LocalFileMng::loadPlayList( const std::string& filename) { - std::string playlistInfoFile = patternname; + std::string playlistInfoFile = filename; std::ifstream verify( playlistInfoFile.c_str() , std::ios::in | std::ios::binary ); if ( verify == NULL ) { - //ERRORLOG( "Load Playlist: Data file " + playlistInfoFile + " not found." ); - return 0; + return 1; } - QDomDocument doc = LocalFileMng::openXmlDocument( QString( patternname.c_str() ) ); + QDomDocument doc = LocalFileMng::openXmlDocument( QString( filename.c_str() ) ); Hydrogen::get_instance()->m_PlayList.clear(); QDomNode rootNode = doc.firstChildElement( "playlist" ); // root element if ( rootNode.isNull() ) { ERRORLOG( "Error reading playlist: playlist node not found" ); - return 0; + return 1; } QDomNode playlistNode = rootNode.firstChildElement( "Songs" ); if ( ! playlistNode.isNull() ) { - // new code :) Hydrogen::get_instance()->m_PlayList.clear(); QDomNode nextNode = playlistNode.firstChildElement( "next" ); while ( ! nextNode.isNull() ) { @@ -768,12 +816,6 @@ void LocalFileMng::writeXmlString( QDomNode parent, const QString& name, const QString& text ) { - /* - TiXmlElement versionNode( name.toAscii() ); - TiXmlText versionText( text.toAscii() ); - versionNode.appendChild( versionText ); - parent->appendChild( versionNode ); - */ QDomDocument doc; QDomElement elem = doc.createElement( name ); QDomText t = doc.createTextNode( text ); @@ -893,8 +935,6 @@ .arg( enc ) .toLocal8Bit(); - //_INFOLOG( QString("Using '%1' encoding for TinyXML file").arg(enc) ); - while( !file.atEnd() ) { line = file.readLine(); LocalFileMng::convertFromTinyXMLString( &line ); @@ -1036,12 +1076,6 @@ LocalFileMng::writeXmlString( songNode, "humanize_velocity", QString("%1").arg( song->get_humanize_velocity_value() ) ); LocalFileMng::writeXmlString( songNode, "swing_factor", QString("%1").arg( song->get_swing_factor() ) ); - /* LocalFileMng::writeXmlBool( &songNode, "delayFXEnabled", song->m_bDelayFXEnabled ); - LocalFileMng::writeXmlString( &songNode, "delayFXWetLevel", QString("%1").arg( song->m_fDelayFXWetLevel ) ); - LocalFileMng::writeXmlString( &songNode, "delayFXFeedback", QString("%1").arg( song->m_fDelayFXFeedback ) ); - LocalFileMng::writeXmlString( &songNode, "delayFXTime", QString("%1").arg( song->m_nDelayFXTime ) ); - */ - // instrument list QDomNode instrumentListNode = doc.createElement( "instrumentList" ); unsigned nInstrument = song->get_instrument_list()->size(); @@ -1054,8 +1088,8 @@ QDomNode instrumentNode = doc.createElement( "instrument" ); LocalFileMng::writeXmlString( instrumentNode, "id", QString("%1").arg( instr->get_id() ) ); - //LocalFileMng::writeXmlString( instrumentNode, "drumkit", instr->get_drumkit_name() ); LocalFileMng::writeXmlString( instrumentNode, "name", instr->get_name() ); + LocalFileMng::writeXmlString( instrumentNode, "drumkit", instr->get_drumkit_name() ); LocalFileMng::writeXmlString( instrumentNode, "volume", QString("%1").arg( instr->get_volume() ) ); LocalFileMng::writeXmlBool( instrumentNode, "isMuted", instr->is_muted() ); LocalFileMng::writeXmlString( instrumentNode, "pan_L", QString("%1").arg( instr->get_pan_l() ) ); @@ -1263,40 +1297,42 @@ songNode.appendChild( ladspaFxNode ); doc.appendChild( songNode ); + + //bpm time line + QDomNode bpmTimeLine = doc.createElement( "BPMTimeLine" ); + if(Hydrogen::get_instance()->m_timelinevector.size() >= 1 ){ + for ( int t = 0; t < static_cast(Hydrogen::get_instance()->m_timelinevector.size()); t++){ + QDomNode newBPMNode = doc.createElement( "newBPM" ); + LocalFileMng::writeXmlString( newBPMNode, "BAR",QString("%1").arg( Hydrogen::get_instance()->m_timelinevector[t].m_htimelinebeat )); + LocalFileMng::writeXmlString( newBPMNode, "BPM", QString("%1").arg( Hydrogen::get_instance()->m_timelinevector[t].m_htimelinebpm ) ); + bpmTimeLine.appendChild( newBPMNode ); + } + } + songNode.appendChild( bpmTimeLine ); + + //time line tag + QDomNode timeLineTag = doc.createElement( "timeLineTag" ); + if(Hydrogen::get_instance()->m_timelinetagvector.size() >= 1 ){ + for ( int t = 0; t < static_cast(Hydrogen::get_instance()->m_timelinetagvector.size()); t++){ + QDomNode newTAGNode = doc.createElement( "newTAG" ); + LocalFileMng::writeXmlString( newTAGNode, "BAR",QString("%1").arg( Hydrogen::get_instance()->m_timelinetagvector[t].m_htimelinetagbeat )); + LocalFileMng::writeXmlString( newTAGNode, "TAG", QString("%1").arg( Hydrogen::get_instance()->m_timelinetagvector[t].m_htimelinetag ) ); + timeLineTag.appendChild( newTAGNode ); + } + } + songNode.appendChild( timeLineTag ); + QFile file(filename); if ( !file.open(QIODevice::WriteOnly) ) - rv = 1; - -//bpm time line - QDomNode bpmTimeLine = doc.createElement( "BPMTimeLine" ); - if(Hydrogen::get_instance()->m_timelinevector.size() >= 1 ){ - for ( int t = 0; t < static_cast(Hydrogen::get_instance()->m_timelinevector.size()); t++){ - QDomNode newBPMNode = doc.createElement( "newBPM" ); - LocalFileMng::writeXmlString( newBPMNode, "BAR",QString("%1").arg( Hydrogen::get_instance()->m_timelinevector[t].m_htimelinebeat )); - LocalFileMng::writeXmlString( newBPMNode, "BPM", QString("%1").arg( Hydrogen::get_instance()->m_timelinevector[t].m_htimelinebpm ) ); - bpmTimeLine.appendChild( newBPMNode ); - } - } - songNode.appendChild( bpmTimeLine ); - -//time line tag - QDomNode timeLineTag = doc.createElement( "timeLineTag" ); - if(Hydrogen::get_instance()->m_timelinetagvector.size() >= 1 ){ - for ( int t = 0; t < static_cast(Hydrogen::get_instance()->m_timelinetagvector.size()); t++){ - QDomNode newTAGNode = doc.createElement( "newTAG" ); - LocalFileMng::writeXmlString( newTAGNode, "BAR",QString("%1").arg( Hydrogen::get_instance()->m_timelinetagvector[t].m_htimelinetagbeat )); - LocalFileMng::writeXmlString( newTAGNode, "TAG", QString("%1").arg( Hydrogen::get_instance()->m_timelinetagvector[t].m_htimelinetag ) ); - timeLineTag.appendChild( newTAGNode ); - } - } - songNode.appendChild( timeLineTag ); + rv = 1; QTextStream TextStream( &file ); doc.save( TextStream, 1 ); - file.close(); - + if( file.size() == 0) + rv = 1; + file.close(); if( rv ) { WARNINGLOG("File save reported an error."); @@ -1304,6 +1340,7 @@ song->__is_modified = false; INFOLOG("Save was successful."); } + song->set_filename( filename ); return rv; diff -Nru hydrogen-0.9.6~beta1/src/core/src/midi_action.cpp hydrogen-0.9.6~beta2/src/core/src/midi_action.cpp --- hydrogen-0.9.6~beta1/src/core/src/midi_action.cpp 2011-11-04 23:35:12.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/midi_action.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,10 @@ << "PLAY/PAUSE_TOGGLE" << "STOP" << "PAUSE" + << "RECORD_READY" + << "RECORD/STROBE_TOGGLE" + << "RECORD_STROBE" + << "RECORD_EXIT" << "MUTE" << "UNMUTE" << "MUTE_TOGGLE" @@ -135,6 +140,7 @@ << "BPM_INCR" << "BPM_DECR" << "BPM_CC_RELATIVE" + << "BPM_FINE_CC_RELATIVE" << "MASTER_VOLUME_RELATIVE" << "MASTER_VOLUME_ABSOLUTE" << "STRIP_VOLUME_RELATIVE" @@ -148,12 +154,19 @@ << "EFFECT3_LEVEL_ABSOLUTE" << "EFFECT4_LEVEL_ABSOLUTE" << "SELECT_NEXT_PATTERN" + << "SELECT_NEXT_PATTERN_CC_ABSOLUT" << "SELECT_NEXT_PATTERN_PROMPTLY" + << "SELECT_AND_PLAY_PATTERN" << "PAN_RELATIVE" << "PAN_ABSOLUTE" << "BEATCOUNTER" << "TAP_TEMPO" - << "SELECT_INSTRUMENT"; + << "PLAYLIST_NEXT_SONG" + << "PLAYLIST_PREV_SONG" + << "TOGGLE_METRONOME" + << "SELECT_INSTRUMENT" + << "UNDO_ACTION" + << "REDO_ACTION"; eventList << "" << "MMC_PLAY" @@ -163,6 +176,7 @@ << "MMC_REWIND" << "MMC_RECORD_STROBE" << "MMC_RECORD_EXIT" + << "MMC_RECORD_READY" << "MMC_PAUSE" << "NOTE" << "CC"; @@ -273,23 +287,51 @@ return true; } - if( sActionString == "SELECT_NEXT_PATTERN" ){ + if( sActionString == "SELECT_NEXT_PATTERN" ){ bool ok; int row = pAction->getParameter1().toInt(&ok,10); if( row> pEngine->getSong()->get_pattern_list()->size() -1 ) return false; - pEngine->setSelectedPatternNumber( row ); - pEngine->sequencer_setNextPattern( row, false, true ); + if(Preferences::get_instance()->patternModePlaysSelected()) + pEngine->setSelectedPatternNumber( row ); + else + pEngine->sequencer_setNextPattern( row, false, true ); return true; } - if( sActionString == "SELECT_NEXT_PATTERN_PROMPTLY" ){ + if( sActionString == "SELECT_NEXT_PATTERN_CC_ABSOLUT" ){ + bool ok; + int row = pAction->getParameter2().toInt(&ok,10); + if( row> pEngine->getSong()->get_pattern_list()->size() -1 ) + return false; + if(Preferences::get_instance()->patternModePlaysSelected()) + pEngine->setSelectedPatternNumber( row ); + else + return true;// only usefully in normal pattern mode + return true; + } + + if( sActionString == "SELECT_NEXT_PATTERN_PROMPTLY" ){// obsolete, use SELECT_NEXT_PATTERN_CC_ABSOLUT instead bool ok; int row = pAction->getParameter2().toInt(&ok,10); pEngine->setSelectedPatternNumberWithoutGuiEvent( row ); return true; } + if( sActionString == "SELECT_AND_PLAY_PATTERN"){ + bool ok; + int row = pAction->getParameter1().toInt(&ok,10); + pEngine->setSelectedPatternNumber( row ); + pEngine->sequencer_setNextPattern( row, false, true ); + + int nState = pEngine->getState(); + if ( nState == STATE_READY ){ + pEngine->sequencer_play(); + } + + return true; + } + if( sActionString == "SELECT_INSTRUMENT" ){ bool ok; int instrument_number = pAction->getParameter2().toInt(&ok,10) ; @@ -603,6 +645,48 @@ return true; } + if( sActionString == "BPM_FINE_CC_RELATIVE" ){ + /* + * increments/decrements the BPM + * this is useful if the bpm is set by a rotary control knob + */ + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + int mult = 1; + + //second parameter of cc command + //this value should be 1 to decrement and something other then 1 to increment the bpm + int cc_param = 1; + + //this Action should be triggered only by CC commands + + bool ok; + mult = pAction->getParameter1().toInt(&ok,10); + cc_param = pAction->getParameter2().toInt(&ok,10); + + if( lastBpmChangeCCParameter == -1) + { + lastBpmChangeCCParameter = cc_param; + } + + Song* pSong = pEngine->getSong(); + + if ( lastBpmChangeCCParameter >= cc_param && pSong->__bpm < 300) { + pEngine->setBPM( pSong->__bpm - 0.01*mult ); + } + + if ( lastBpmChangeCCParameter < cc_param && pSong->__bpm > 40 ) { + pEngine->setBPM( pSong->__bpm + 0.01*mult ); + } + + lastBpmChangeCCParameter = cc_param; + + AudioEngine::get_instance()->unlock(); + + return true; + } + if( sActionString == "BPM_INCR" ){ AudioEngine::get_instance()->lock( RIGHT_HERE ); @@ -622,8 +706,6 @@ return true; } - - if( sActionString == "BPM_DECR" ){ AudioEngine::get_instance()->lock( RIGHT_HERE ); @@ -652,6 +734,74 @@ pEngine->setTimelineBpm(); return true; } - - return false; + + if( sActionString == "PLAYLIST_NEXT_SONG"){ + int songnumber = Playlist::get_instance()->getActiveSongNumber(); + if(songnumber+1 >= 0 && songnumber+1 <= pEngine->m_PlayList.size()-1){ + Playlist::get_instance()->setNextSongByNumber( songnumber + 1 ); + } + return true; + } + + if( sActionString == "PLAYLIST_PREV_SONG"){ + int songnumber = Playlist::get_instance()->getActiveSongNumber(); + if(songnumber-1 >= 0 && songnumber-1 <= pEngine->m_PlayList.size()-1){ + Playlist::get_instance()->setNextSongByNumber( songnumber - 1 ); + } + return true; + } + + if( sActionString == "RECORD_READY"){ + if ( pEngine->getState() != STATE_PLAYING ) { + if (!Preferences::get_instance()->getRecordEvents()) { + Preferences::get_instance()->setRecordEvents(true); + } + else { + Preferences::get_instance()->setRecordEvents(false); + } + } + return true; + } + if( sActionString == "RECORD/STROBE_TOGGLE"){ + if (!Preferences::get_instance()->getRecordEvents()) { + Preferences::get_instance()->setRecordEvents(true); + } + else { + Preferences::get_instance()->setRecordEvents(false); + } + return true; + } + + if( sActionString == "RECORD_STROBE"){ + + if (!Preferences::get_instance()->getRecordEvents()) { + Preferences::get_instance()->setRecordEvents(true); + } + return true; + } + + if( sActionString == "RECORD_EXIT"){ + + if (Preferences::get_instance()->getRecordEvents()) { + Preferences::get_instance()->setRecordEvents(false); + } + return true; + } + + if( sActionString == "TOGGLE_METRONOME"){ + + Preferences::get_instance()->m_bUseMetronome = !Preferences::get_instance()->m_bUseMetronome; + return true; + } + + if( sActionString == "UNDO_ACTION"){ + EventQueue::get_instance()->push_event( EVENT_UNDO_REDO, 0);// 0 = undo + return true; + } + + if( sActionString == "REDO_ACTION"){ + EventQueue::get_instance()->push_event( EVENT_UNDO_REDO, 1);// 1 = redo + return true; + } + return false; } diff -Nru hydrogen-0.9.6~beta1/src/core/src/object.cpp hydrogen-0.9.6~beta2/src/core/src/object.cpp --- hydrogen-0.9.6~beta1/src/core/src/object.cpp 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/object.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -27,6 +27,20 @@ #include #include + +/** +* @class Object +* +* @brief Base class of all components of hydrogen. +* +* Every component of hydrogen is inherited from the +* Object class. Each object has a qualified name +* and gets registered in a memory map at creation. +* This memory map helps to debug memory leaks and +* can be printed at any time. +* +*/ + namespace H2Core { Logger* Object::__logger = 0; diff -Nru hydrogen-0.9.6~beta1/src/core/src/preferences.cpp hydrogen-0.9.6~beta2/src/core/src/preferences.cpp --- hydrogen-0.9.6~beta1/src/core/src/preferences.cpp 2011-11-04 23:07:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/preferences.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -73,10 +73,6 @@ m_brestartLash = false; m_bsetLash = false; -#ifdef H2CORE_HAVE_JACKSESSION - m_bjackSessionUseSessionDir = false; -#endif - //init pre delete default m_nRecPreDelete = 0; m_nRecPostDelete = 0; @@ -89,6 +85,7 @@ //rubberband bpm change queue m_useTheRubberbandBpmChangeEvent = false; + __rubberBandCalcTime = 5; QString rubberBandCLIPath = getenv( "PATH" ); QStringList rubberBandCLIPathList = rubberBandCLIPath.split(":");//linx use ":" as seperator. maybe windows and osx use other seperators @@ -157,14 +154,6 @@ __playsamplesonclicking = false; // audio file browser __playselectedinstrument = false; // midi keyboard and keyboard play only selected instrument - // __rightclickedpattereditor - // 0 = note length - // 1 = note off" - // 2 = edit velocity - // 3 = edit pan - // 4 = edit lead lag - __rightclickedpattereditor = 0; //right click into pattern editor add note-off-note or edit note-length - recordEvents = false; // not recording by default destructiveRecord = false; // not destructively recording by default punchInPos = 0; @@ -172,7 +161,7 @@ __expandSongItem = true; //SoundLibraryPanel __expandPatternItem = true; //SoundLibraryPanel - __usetimeline = false; // use timeline + __useTimelineBpm = false; // use timeline ///////////////////////////////////////////////////////////////////////// @@ -395,22 +384,19 @@ m_brestoreLastPlaylist = LocalFileMng::readXmlBool( rootNode, "restoreLastPlaylist", m_brestoreLastPlaylist ); m_bPatternModePlaysSelected = LocalFileMng::readXmlBool( rootNode, "patternModePlaysSelected", TRUE ); m_bUseLash = LocalFileMng::readXmlBool( rootNode, "useLash", FALSE ); - __usetimeline = LocalFileMng::readXmlBool( rootNode, "useTimeLine", __usetimeline ); + __useTimelineBpm = LocalFileMng::readXmlBool( rootNode, "useTimeLine", __useTimelineBpm ); maxBars = LocalFileMng::readXmlInt( rootNode, "maxBars", 400 ); m_nDefaultUILayout = LocalFileMng::readXmlInt( rootNode, "defaultUILayout", UI_LAYOUT_SINGLE_PANE ); + m_nLastOpenTab = LocalFileMng::readXmlInt( rootNode, "lastOpenTab", 0 ); //restore the right m_bsetlash value m_bsetLash = m_bUseLash; - + m_useTheRubberbandBpmChangeEvent = LocalFileMng::readXmlBool( rootNode, "useTheRubberbandBpmChangeEvent", m_useTheRubberbandBpmChangeEvent ); m_nRecPreDelete = LocalFileMng::readXmlInt( rootNode, "preDelete", 0 ); m_nRecPostDelete = LocalFileMng::readXmlInt( rootNode, "postDelete", 0 ); hearNewNotes = LocalFileMng::readXmlBool( rootNode, "hearNewNotes", hearNewNotes ); quantizeEvents = LocalFileMng::readXmlBool( rootNode, "quantizeEvents", quantizeEvents ); - -#ifdef H2CORE_HAVE_JACKSESSION - m_bjackSessionUseSessionDir = LocalFileMng::readXmlBool( rootNode, "JackSessionUseSessionDir", m_bjackSessionUseSessionDir ); -#endif //rubberband if( readPrefFileforotherplaces ){ @@ -751,19 +737,18 @@ LocalFileMng::writeXmlString( rootNode, "patternModePlaysSelected", m_bPatternModePlaysSelected ? "true": "false" ); LocalFileMng::writeXmlString( rootNode, "useLash", m_bsetLash ? "true": "false" ); - LocalFileMng::writeXmlString( rootNode, "useTimeLine", __usetimeline ? "true": "false" ); + LocalFileMng::writeXmlString( rootNode, "useTimeLine", __useTimelineBpm ? "true": "false" ); LocalFileMng::writeXmlString( rootNode, "maxBars", QString::number( maxBars ) ); LocalFileMng::writeXmlString( rootNode, "defaultUILayout", QString::number( m_nDefaultUILayout ) ); + LocalFileMng::writeXmlString( rootNode, "lastOpenTab", QString::number( m_nLastOpenTab ) ); + + LocalFileMng::writeXmlString( rootNode, "useTheRubberbandBpmChangeEvent", m_useTheRubberbandBpmChangeEvent ? "true": "false" ); LocalFileMng::writeXmlString( rootNode, "preDelete", QString("%1").arg(m_nRecPreDelete) ); LocalFileMng::writeXmlString( rootNode, "postDelete", QString("%1").arg(m_nRecPostDelete) ); -#ifdef H2CORE_HAVE_JACKSESSION - LocalFileMng::writeXmlString( rootNode, "JackSessionUseSessionDir", m_bjackSessionUseSessionDir ? "true": "false" ); -#endif - //show development version warning LocalFileMng::writeXmlString( rootNode, "showDevelWarning", m_bShowDevelWarning ? "true": "false" ); diff -Nru hydrogen-0.9.6~beta1/src/core/src/sampler/sampler.cpp hydrogen-0.9.6~beta2/src/core/src/sampler/sampler.cpp --- hydrogen-0.9.6~beta1/src/core/src/sampler/sampler.cpp 2011-07-22 14:41:09.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/core/src/sampler/sampler.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -591,9 +591,21 @@ if ( ( nSamplePos + 1 ) >= nSampleFrames ) { //we reach the last audioframe. //set this last frame to zero do nothin wrong. - fVal_L = 0.0; - fVal_R = 0.0; + fVal_L = 0.0; + fVal_R = 0.0; } else { + // some interpolation methods need 4 frames data. + float last_l; + float last_r; + if ( ( nSamplePos + 2 ) >= nSampleFrames ) { + last_l = 0.0; + last_r = 0.0; + }else + { + last_l = pSample_data_L[nSamplePos + 2]; + last_r = pSample_data_R[nSamplePos + 2]; + } + switch( __interpolateMode ){ case LINEAR: @@ -607,16 +619,16 @@ fVal_R = cosine_Interpolate( pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], fDiff); break; case THIRD: - fVal_L = third_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], pSample_data_L[nSamplePos + 2] ,fDiff); - fVal_R = third_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], pSample_data_R[nSamplePos + 2], fDiff); + fVal_L = third_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); + fVal_R = third_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; case CUBIC: - fVal_L = cubic_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], pSample_data_L[nSamplePos + 2] ,fDiff); - fVal_R = cubic_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], pSample_data_R[nSamplePos + 2], fDiff); + fVal_L = cubic_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); + fVal_R = cubic_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; case HERMITE: - fVal_L = hermite_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], pSample_data_L[nSamplePos + 2] ,fDiff); - fVal_R = hermite_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], pSample_data_R[nSamplePos + 2], fDiff); + fVal_L = hermite_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); + fVal_R = hermite_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; } } @@ -693,6 +705,18 @@ fVal_L = 0.0; fVal_R = 0.0; } else { + // some interpolation methods need 4 frames data. + float last_l; + float last_r; + if ( ( nSamplePos + 2 ) >= nSampleFrames ) { + last_l = 0.0; + last_r = 0.0; + }else + { + last_l = pSample_data_L[nSamplePos + 2]; + last_r = pSample_data_R[nSamplePos + 2]; + } + switch( __interpolateMode ){ case LINEAR: @@ -706,16 +730,16 @@ fVal_R = cosine_Interpolate( pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], fDiff); break; case THIRD: - fVal_L = third_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], pSample_data_L[nSamplePos + 2] ,fDiff); - fVal_R = third_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], pSample_data_R[nSamplePos + 2], fDiff); + fVal_L = third_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); + fVal_R = third_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; case CUBIC: - fVal_L = cubic_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], pSample_data_L[nSamplePos + 2] ,fDiff); - fVal_R = cubic_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], pSample_data_R[nSamplePos + 2], fDiff); + fVal_L = cubic_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); + fVal_R = cubic_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; case HERMITE: - fVal_L = hermite_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], pSample_data_L[nSamplePos + 2] ,fDiff); - fVal_R = hermite_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], pSample_data_R[nSamplePos + 2], fDiff); + fVal_L = hermite_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); + fVal_R = hermite_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; } // methode Interpolate produce an extra function call and eat much more time here. diff -Nru hydrogen-0.9.6~beta1/src/gui/src/AboutDialog.cpp hydrogen-0.9.6~beta2/src/gui/src/AboutDialog.cpp --- hydrogen-0.9.6~beta1/src/gui/src/AboutDialog.cpp 2011-11-29 23:07:08.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/AboutDialog.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -66,6 +66,7 @@ authorList.push_back( Author( "Christian Vorhof", "", "Interface design concept" ) ); authorList.push_back( Author( "Daniil Kolpakov", "", "" ) ); authorList.push_back( Author( "Daniel Tonda Castillo", "", "Spanish manual" ) ); + authorList.push_back( Author( "Dave Allan", "", "Manual review" ) ); authorList.push_back( Author( "Dave Fancella", "", "" ) ); authorList.push_back( Author( "Dave Phillips", "", "Bug reports, ideas" ) ); authorList.push_back( Author( "Derrick Karpo", "", "Patches, testing" ) ); @@ -103,10 +104,9 @@ QString sAuthors; sAuthors += tr( "Main coder and mantainer:
    " ); - sAuthors += "

    • Alessandro Cominu (aka Comix)
      "; - sAuthors += "

    "; - - sAuthors += QString( "" ) + trUtf8( "Translator:%1Alessandro Cominu" ).arg( "
    • " ) + QString( "

    " ); + sAuthors += "
    • Alessandro Cominu (aka Comix) [2001-2008]

    • "; + sAuthors += "
    • Michael Wolkstein (aka Wolke) [2008-now]

    • "; + sAuthors += "
    • Sebastian Moors (aka Mauser) [2008-now]

    "; sAuthors += "Thanks to:"; @@ -121,7 +121,7 @@ sAuthors += ""; - authorsTxt->setText( sAuthors ); + authorsText->setText( sAuthors ); logoLabel->setPixmap( QPixmap( Skin::getImagePath() +"/about/aboutLogo.png" ) ); } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/EventListener.h hydrogen-0.9.6~beta2/src/gui/src/EventListener.h --- hydrogen-0.9.6~beta1/src/gui/src/EventListener.h 2011-10-21 16:00:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/EventListener.h 2012-05-25 12:19:45.000000000 +0000 @@ -40,6 +40,7 @@ virtual void progressEvent( int nValue ) { UNUSED( nValue ); } virtual void jacksessionEvent( int nValue) { UNUSED( nValue ); } virtual void playlistLoadSongEvent( int nIndex ){ UNUSED( nIndex ); } + virtual void undoRedoActionEvent( int nValue ){ UNUSED( nValue ); } virtual ~EventListener() {} }; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/ExportSongDialog.cpp hydrogen-0.9.6~beta2/src/gui/src/ExportSongDialog.cpp --- hydrogen-0.9.6~beta1/src/gui/src/ExportSongDialog.cpp 2011-09-29 12:04:51.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/ExportSongDialog.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -35,10 +35,14 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include #include @@ -59,7 +63,7 @@ exportTypeCombo->addItem(trUtf8("Export to seperate tracks")); exportTypeCombo->addItem(trUtf8("Both")); - HydrogenApp::get_instance()->addEventListener( this ); + HydrogenApp::get_instance()->addEventListener( this ); m_pProgressBar->setValue( 0 ); sampleRateCombo->setCurrentIndex(1); @@ -78,7 +82,39 @@ m_sExtension = ".wav"; m_bOverwriteFiles = false; + // use of rubberband batch + if(checkUseOfRubberband()){ + b_oldRubberbandBatchMode = Preferences::get_instance()->getRubberBandBatchMode(); + toggleRubberbandCheckBox->setChecked(Preferences::get_instance()->getRubberBandBatchMode()); + connect(toggleRubberbandCheckBox, SIGNAL(toggled(bool)), this, SLOT(toggleRubberbandBatchMode( bool ))); + }else + { + b_oldRubberbandBatchMode = Preferences::get_instance()->getRubberBandBatchMode(); + toggleRubberbandCheckBox->setEnabled( false ); + } + + + // use of timeline + if( Hydrogen::get_instance()->m_timelinevector.size() > 0 ){ + toggleTimeLineBPMCheckBox->setChecked(Preferences::get_instance()->getUseTimelineBpm()); + b_oldTimeLineBPMMode = Preferences::get_instance()->getUseTimelineBpm(); + connect(toggleTimeLineBPMCheckBox, SIGNAL(toggled(bool)), this, SLOT(togglTimeLineBPMMode( bool ))); + }else + { + b_oldTimeLineBPMMode = Preferences::get_instance()->getUseTimelineBpm(); + toggleTimeLineBPMCheckBox->setEnabled( false ); + } + + // use of interpolation mode + m_oldInterpolation = AudioEngine::get_instance()->get_sampler()->getInterpolateMode(); + resampleComboBox->setCurrentIndex( m_oldInterpolation ); + connect(resampleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resampleComboBoIndexChanged(int))); + + // if rubberbandBatch calculate time needed by lib rubberband to resample samples + if(b_oldRubberbandBatchMode){ + calculateRubberbandTime(); + } } @@ -152,7 +188,6 @@ m_bOverwriteFiles = false; - /* If the song has a tempo change, notify the user * that hydrogen is unable export songs with * tempo changes correctly @@ -162,13 +197,8 @@ bool warn = Preferences::get_instance()->getShowExportWarning(); std::vector timelineVector = engine->m_timelinevector; - if( timelineVector.size() > 0 ){ - int res = QMessageBox::information( this, "Hydrogen", tr( "This version of hydrogen is not able to export songs with tempo changes. If you proceed, the song will be exported without tempo changes."), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll); - if (res == QMessageBox::No ) return; - if (res == QMessageBox::YesToAll ) Preferences::get_instance()->setShowExportWarning(true); - } - - /* 0: Export to single track + + /* 0: Export to single track * 1: Export to multiple tracks * 2: Export to both */ @@ -207,47 +237,46 @@ void ExportSongDialog::exportTracks() { - Song *pSong = Hydrogen::get_instance()->getSong(); + Song *pSong = Hydrogen::get_instance()->getSong(); if( m_nInstrument <= pSong->get_instrument_list()->size() -1 ){ - bool instrumentexists = false; - //if a instrument contains no notes we jump to the next instrument - unsigned nPatterns = pSong->get_pattern_list()->size(); - for ( unsigned i = 0; i < nPatterns; i++ ) { - Pattern *pat = pSong->get_pattern_list()->get( i ); - const Pattern::notes_t* notes = pat->get_notes(); - FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) { - Note *pNote = it->second; - assert( pNote ); + bool instrumentexists = false; + //if a instrument contains no notes we jump to the next instrument + unsigned nPatterns = pSong->get_pattern_list()->size(); + for ( unsigned i = 0; i < nPatterns; i++ ) { + Pattern *pat = pSong->get_pattern_list()->get( i ); + const Pattern::notes_t* notes = pat->get_notes(); + FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) { + Note *pNote = it->second; + assert( pNote ); if( pNote->get_instrument()->get_name() == Hydrogen::get_instance()->getSong()->get_instrument_list()->get(m_nInstrument)->get_name() ){ - instrumentexists = true; - break; - } + instrumentexists = true; + break; + } - } - } + } + } - if( !instrumentexists ){ + if( !instrumentexists ){ if( m_nInstrument == Hydrogen::get_instance()->getSong()->get_instrument_list()->size() -1 ){ - m_bExportTrackouts = false;// - HydrogenApp::get_instance()->getMixer()->soloClicked( m_nInstrument );//solo instrument. this will disable all other instrument-solos - HydrogenApp::get_instance()->getMixer()->soloClicked( m_nInstrument );//unsolo this instrument because exporting is finished + m_bExportTrackouts = false; + HydrogenApp::get_instance()->getMixer()->unmuteAll( true ); m_nInstrument = 0; - return; + return; }else { m_nInstrument++; exportTracks(); return; - } - } + } + } QStringList filenameList = exportNameTxt->text().split( m_sExtension ); - + QString firstItem; if( !filenameList.isEmpty() ){ firstItem = filenameList.first(); - } + } QString newItem = firstItem + "-" + Hydrogen::get_instance()->getSong()->get_instrument_list()->get(m_nInstrument)->get_name(); QString filename = newItem.append(m_sExtension); @@ -256,25 +285,32 @@ int res = QMessageBox::information( this, "Hydrogen", tr( "The file %1 exists. \nOverwrite the existing file?").arg(filename), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll ); if (res == QMessageBox::No ) return; if (res == QMessageBox::YesToAll ) m_bOverwriteFiles = true; - } + } - Hydrogen::get_instance()->stopExportSong(); - m_bExporting = false; + //Hydrogen::get_instance()->stopExportSong(); + Hydrogen::get_instance()->stopExportSong( false ); + m_bExporting = false; HydrogenApp::get_instance()->getMixer()->soloClicked( m_nInstrument ); - //Preferences::get_instance()->m_bUseMetronome = !Preferences::get_instance()->m_bUseMetronome; - Hydrogen::get_instance()->startExportSong( filename, sampleRateCombo->currentText().toInt(), sampleDepthCombo->currentText().toInt() ); - + Hydrogen::get_instance()->startExportSong( filename, sampleRateCombo->currentText().toInt(), sampleDepthCombo->currentText().toInt() ); + if(! (m_nInstrument == Hydrogen::get_instance()->getSong()->get_instrument_list()->size() -1 )){ - m_nInstrument++; + m_nInstrument++; } - } + } + } void ExportSongDialog::on_closeBtn_clicked() { - Hydrogen::get_instance()->stopExportSong(); + Hydrogen::get_instance()->stopExportSong( true ); m_bExporting = false; + if(Preferences::get_instance()->getRubberBandBatchMode()){ + EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); + } + Preferences::get_instance()->setRubberBandBatchMode( b_oldRubberbandBatchMode ); + Preferences::get_instance()->setUseTimelineBpm( b_oldTimeLineBPMMode ); + setResamplerMode(m_oldInterpolation); accept(); } @@ -411,48 +447,198 @@ } if( filename.endsWith( ".ogg" ) || filename.endsWith( ".OGG" ) ){ + if( templateCombo->currentIndex() != 9 ){ templateCombo->setCurrentIndex( 9 );//ogg - } + } + } else if( filename.endsWith( ".flac" ) || filename.endsWith( ".FLAC" ) ){ label->show(); label_2->show(); - templateCombo->setCurrentIndex( 8 );//flac + if( templateCombo->currentIndex() != 8 ){ + templateCombo->setCurrentIndex( 8 );//flac + } } else if( filename.endsWith( ".aiff" ) || filename.endsWith( ".AIFF" ) ){ label->show(); label_2->show(); - templateCombo->setCurrentIndex( 5 );//aiff + if( templateCombo->currentIndex() < 5 || templateCombo->currentIndex() > 7 ){ + templateCombo->setCurrentIndex( 5 );//aiff + } } else if( filename.endsWith( ".wav" ) || filename.endsWith( ".WAV" ) ){ label->show(); label_2->show(); - templateCombo->setCurrentIndex( 0 );//wav - } -} + if( templateCombo->currentIndex() > 4 ){ + templateCombo->setCurrentIndex( 0 );//wav + } + } +} void ExportSongDialog::progressEvent( int nValue ) { m_pProgressBar->setValue( nValue ); - if ( nValue == 100 ) { - - m_bExporting = false; - //Preferences::get_instance()->m_bUseMetronome = !Preferences::get_instance()->m_bUseMetronome; + if ( nValue == 100 ) { + + m_bExporting = false; if( m_nInstrument == Hydrogen::get_instance()->getSong()->get_instrument_list()->size() -1 ){ - HydrogenApp::get_instance()->getMixer()->soloClicked( m_nInstrument ); + HydrogenApp::get_instance()->getMixer()->unmuteAll( false ); m_nInstrument = 0; - m_bExportTrackouts = false; + m_bExportTrackouts = false; - } + } - //QFile check( exportNameTxt->text() ); - //if ( ! check.exists() ) { - // QMessageBox::information( this, "Hydrogen", trUtf8("Export failed!") ); - //} - - if( m_bExportTrackouts ){ - exportTracks(); - } - } + if( m_bExportTrackouts ){ + exportTracks(); + } + } + + if ( nValue < 100 ) { + closeBtn->setEnabled(false); + resampleComboBox->setEnabled(false); + + }else + { + closeBtn->setEnabled(true); + resampleComboBox->setEnabled(true); + } +} + +void ExportSongDialog::toggleRubberbandBatchMode(bool toggled) +{ + Preferences::get_instance()->setRubberBandBatchMode(toggled); + if(toggled){ + calculateRubberbandTime(); + } +} + +void ExportSongDialog::togglTimeLineBPMMode(bool toggled) +{ + Preferences::get_instance()->setUseTimelineBpm(toggled); +} + +void ExportSongDialog::resampleComboBoIndexChanged(int index ) +{ + setResamplerMode(index); +} + +void ExportSongDialog::setResamplerMode(int index) +{ + switch ( index ){ + case 0: + AudioEngine::get_instance()->get_sampler()->setInterpolateMode( Sampler::LINEAR ); + break; + case 1: + AudioEngine::get_instance()->get_sampler()->setInterpolateMode( Sampler::COSINE ); + break; + case 2: + AudioEngine::get_instance()->get_sampler()->setInterpolateMode( Sampler::THIRD ); + break; + case 3: + AudioEngine::get_instance()->get_sampler()->setInterpolateMode( Sampler::CUBIC ); + break; + case 4: + AudioEngine::get_instance()->get_sampler()->setInterpolateMode( Sampler::HERMITE ); + break; + } +} + + +void ExportSongDialog::calculateRubberbandTime() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + closeBtn->setEnabled(false); + resampleComboBox->setEnabled(false); + okBtn->setEnabled(false); + Hydrogen* engine = Hydrogen::get_instance(); + float oldBPM = engine->getSong()->__bpm; + float lowBPM = oldBPM; + + if( engine->m_timelinevector.size() >= 1 ){ + for ( int t = 0; t < engine->m_timelinevector.size(); t++){ + if(engine->m_timelinevector[t].m_htimelinebpm < lowBPM){ + lowBPM = engine->m_timelinevector[t].m_htimelinebpm; + } + + } + } + + engine->setBPM(lowBPM); + time_t sTime = time(NULL); + Hydrogen *pEngine = Hydrogen::get_instance(); + Song *song = pEngine->getSong(); + assert(song); + if(song){ + InstrumentList *songInstrList = song->get_instrument_list(); + assert(songInstrList); + for ( unsigned nInstr = 0; nInstr < songInstrList->size(); ++nInstr ) { + Instrument *pInstr = songInstrList->get( nInstr ); + assert( pInstr ); + if ( pInstr ){ + for ( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) { + InstrumentLayer *pLayer = pInstr->get_layer( nLayer ); + if ( pLayer ) { + Sample *pSample = pLayer->get_sample(); + if ( pSample ) { + if( pSample->get_rubberband().use ) { + Sample *newSample = Sample::load( + pSample->get_filepath(), + pSample->get_loops(), + pSample->get_rubberband(), + *pSample->get_velocity_envelope(), + *pSample->get_pan_envelope() + ); + if( !newSample ){ + continue; + } + delete pSample; + // insert new sample from newInstrument + AudioEngine::get_instance()->lock( RIGHT_HERE ); + pLayer->set_sample( newSample ); + AudioEngine::get_instance()->unlock(); + + } + } + } + } + } + } + } + Preferences::get_instance()->setRubberBandCalcTime(time(NULL) - sTime); + engine->setBPM(oldBPM); + closeBtn->setEnabled(true); + resampleComboBox->setEnabled(true); + okBtn->setEnabled(true); + QApplication::restoreOverrideCursor(); + +} + +bool ExportSongDialog::checkUseOfRubberband() +{ + Hydrogen *pEngine = Hydrogen::get_instance(); + Song *song = pEngine->getSong(); + assert(song); + if(song){ + InstrumentList *songInstrList = song->get_instrument_list(); + assert(songInstrList); + for ( unsigned nInstr = 0; nInstr < songInstrList->size(); ++nInstr ) { + Instrument *pInstr = songInstrList->get( nInstr ); + assert( pInstr ); + if ( pInstr ){ + for ( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) { + InstrumentLayer *pLayer = pInstr->get_layer( nLayer ); + if ( pLayer ) { + Sample *pSample = pLayer->get_sample(); + if ( pSample ) { + if( pSample->get_rubberband().use ) { + return true; + } + } + } + } + } + } + } + return false; } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/ExportSongDialog.h hydrogen-0.9.6~beta2/src/gui/src/ExportSongDialog.h --- hydrogen-0.9.6~beta1/src/gui/src/ExportSongDialog.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/ExportSongDialog.h 2012-05-25 12:19:45.000000000 +0000 @@ -52,14 +52,26 @@ void on_okBtn_clicked(); void on_exportNameTxt_textChanged(const QString& text); void on_templateCombo_currentIndexChanged(int index ); + void toggleRubberbandBatchMode(bool toggled); + void togglTimeLineBPMMode(bool toggled); + void resampleComboBoIndexChanged(int index ); private: - bool m_bExporting; + + void setResamplerMode(int index); + void calculateRubberbandTime(); + bool checkUseOfRubberband(); + + bool m_bExporting; void exportTracks(); bool m_bExportTrackouts; bool m_bOverwriteFiles; uint m_nInstrument; QString m_sExtension; + bool b_oldRubberbandBatchMode; + bool b_oldTimeLineBPMMode; + int m_oldInterpolation; + }; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/HydrogenApp.cpp hydrogen-0.9.6~beta2/src/gui/src/HydrogenApp.cpp --- hydrogen-0.9.6~beta1/src/gui/src/HydrogenApp.cpp 2011-10-21 16:00:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/HydrogenApp.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -22,6 +22,11 @@ #include #include +#include +#include +#include +#include +#include #include "HydrogenApp.h" #include "Skin.h" @@ -32,6 +37,7 @@ #include "HelpBrowser.h" #include "LadspaFXProperties.h" #include "InstrumentRack.h" +#include "Director.h" #include "PatternEditor/PatternEditorPanel.h" #include "InstrumentEditor/InstrumentEditorPanel.h" @@ -39,19 +45,14 @@ #include "SongEditor/SongEditorPanel.h" #include "PlaylistEditor/PlaylistDialog.h" #include "SampleEditor/SampleEditor.h" -#include "Director.h" - #include "Mixer/Mixer.h" #include "Mixer/MixerLine.h" +#include "UndoActions.h" + -#include -#include -#include -#include -//#include #include -//#include + using namespace H2Core; @@ -117,7 +118,7 @@ m_pDirector = new Director( 0 ); // m_pSampleEditor = new SampleEditor( 0 ); - showInfoSplash(); // First time information + showInfoSplash(); // First time information } @@ -127,13 +128,9 @@ INFOLOG( "[~HydrogenApp]" ); m_pEventQueueTimer->stop(); + //delete the undo tmp directory - QString dataDir = Preferences::get_instance()->getTmpDirectory(); - QString cmd = QString( "rm -rf \"" ) + dataDir + "\""; - INFOLOG( cmd ); - if ( system( cmd.toLocal8Bit() ) != 0 ) { - ERRORLOG( "Error executing '" + cmd + "'" ); - } + cleanupTemporaryFiles(); delete m_pHelpBrowser; delete m_pAudioEngineInfoForm; @@ -181,11 +178,11 @@ m_pMainForm->resize( mainFormProp.width, mainFormProp.height ); m_pMainForm->move( mainFormProp.x, mainFormProp.y ); - QSplitter *pSplitter = new QSplitter( NULL ); + pSplitter = new QSplitter( NULL ); pSplitter->setOrientation( Qt::Vertical ); pSplitter->setOpaqueResize( true ); - QTabWidget *pTab = new QTabWidget( NULL ); + pTab = new QTabWidget( NULL ); pTab->setStyleSheet("color: white;"); // SONG EDITOR @@ -198,7 +195,7 @@ m_pSongEditorPanel->resize( songEditorProp.width, songEditorProp.height ); if( uiLayout == Preferences::UI_LAYOUT_TABBED) - pTab->addTab( m_pSongEditorPanel, "Song Editor" ); + pTab->addTab( m_pSongEditorPanel, trUtf8("Song Editor") ); // this HBox will contain the InstrumentRack and the Pattern editor QWidget *pSouthPanel = new QWidget( pSplitter ); @@ -211,9 +208,9 @@ m_pInstrumentRack = new InstrumentRack( NULL ); if( uiLayout == Preferences::UI_LAYOUT_TABBED ){ - pTab->setMovable(true); - pTab->setTabsClosable(true); - pTab->addTab( pSouthPanel, " Instrument + Pattern " ); + pTab->setMovable( false ); + pTab->setTabsClosable( false ); + pTab->addTab( pSouthPanel, trUtf8( "Instrument + Pattern") ); } // PATTERN EDITOR @@ -239,8 +236,10 @@ if( uiLayout == Preferences::UI_LAYOUT_SINGLE_PANE) pMainVBox->addWidget( pSplitter ); - else - pMainVBox->addWidget( pTab ); + else { + pMainVBox->addWidget( pTab ); + + } mainArea->setLayout( pMainVBox ); @@ -255,7 +254,7 @@ m_pMixer->move( mixerProp.x, mixerProp.y ); if( uiLayout == Preferences::UI_LAYOUT_TABBED){ - pTab->addTab(m_pMixer,"Mixer"); + pTab->addTab(m_pMixer,trUtf8("Mixer")); } m_pMixer->updateMixer(); @@ -289,10 +288,19 @@ } #endif -// m_pMainForm->showMaximized(); + if( uiLayout == Preferences::UI_LAYOUT_TABBED){ + pTab->setCurrentIndex( Preferences::get_instance()->getLastOpenTab() ); + QObject::connect(pTab, SIGNAL(currentChanged(int)),this,SLOT(currentTabChanged(int))); + } } + +void HydrogenApp::currentTabChanged(int index) +{ + Preferences::get_instance()->setLastOpenTab( index ); +} + void HydrogenApp::closeFXProperties() { #ifdef H2CORE_HAVE_LADSPA @@ -335,7 +343,39 @@ void HydrogenApp::showMixer(bool show) { - m_pMixer->setVisible( show ); + /* + * Switch to Mixer tab with alt+m in tabbed mode, + * otherwise open mixer window + */ + + Preferences *pPref = Preferences::get_instance(); + int uiLayout = pPref->getDefaultUILayout(); + + if( uiLayout == Preferences::UI_LAYOUT_TABBED ) + { + pTab->setCurrentIndex( 2 ); + } else { + m_pMixer->setVisible( show ); + } +} + +void HydrogenApp::showInstrumentPanel(bool show) +{ + /* + * Switch to pattern editor/instrument tab in tabbed mode, + * otherwise hide instrument panel + */ + + Preferences *pPref = Preferences::get_instance(); + int uiLayout = pPref->getDefaultUILayout(); + + if( uiLayout == Preferences::UI_LAYOUT_TABBED ) + { + pTab->setCurrentIndex( 1 ); + getInstrumentRack()->setHidden( show ); + } else { + getInstrumentRack()->setHidden( show ); + } } @@ -521,12 +561,45 @@ case EVENT_PLAYLIST_LOADSONG: pListener->playlistLoadSongEvent( event.value ); break; + + case EVENT_UNDO_REDO: + pListener->undoRedoActionEvent( event.value ); + break; + default: ERRORLOG( QString("[onEventQueueTimer] Unhandled event: %1").arg( event.type ) ); } } - } + } + + // midi notes + while(!pQueue->m_addMidiNoteVector.empty()){ + + int rounds = 1; + if(pQueue->m_addMidiNoteVector[0].b_noteExist)// runn twice, delete old note and add new note. this let the undo stack consistent + rounds = 2; + for(int i = 0; im_addMidiNoteVector[0].m_column, + pQueue->m_addMidiNoteVector[0].m_row, + pQueue->m_addMidiNoteVector[0].m_pattern, + pQueue->m_addMidiNoteVector[0].m_length, + pQueue->m_addMidiNoteVector[0].f_velocity, + pQueue->m_addMidiNoteVector[0].f_pan_L, + pQueue->m_addMidiNoteVector[0].f_pan_R, + 0.0, + pQueue->m_addMidiNoteVector[0].nk_noteKeyVal, + pQueue->m_addMidiNoteVector[0].no_octaveKeyVal, + false, + false, + pQueue->m_addMidiNoteVector[0].b_isMidi, + pQueue->m_addMidiNoteVector[0].b_isInstrumentMode); + + HydrogenApp::get_instance()->m_undoStack->push( action ); + } + pQueue->m_addMidiNoteVector.erase(pQueue->m_addMidiNoteVector.begin()); + + } } @@ -547,3 +620,26 @@ } } + +/** + * Adds temporary file to the list + */ +void HydrogenApp::addTemporaryFile( const QString& path) +{ + temporaryFileList.append( path ); +} + + +/** + * Removes temporary files that were created + * for undo'ing things. + */ +void HydrogenApp::cleanupTemporaryFiles() +{ + for (int i = 0; i < temporaryFileList.size(); ++i){ + Filesystem::rm( temporaryFileList[i] ); + } + + Filesystem::rm( Preferences::get_instance()->getTmpDirectory() ); +} + diff -Nru hydrogen-0.9.6~beta1/src/gui/src/HydrogenApp.h hydrogen-0.9.6~beta2/src/gui/src/HydrogenApp.h --- hydrogen-0.9.6~beta1/src/gui/src/HydrogenApp.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/HydrogenApp.h 2012-05-25 12:19:45.000000000 +0000 @@ -32,6 +32,7 @@ #include #include #include + #include namespace H2Core { @@ -71,6 +72,7 @@ void showPreferencesDialog(); void showMixer(bool bShow); + void showInstrumentPanel(bool); void showAudioEngineInfoForm(); void showPlaylistDialog(); void showDirector(); @@ -89,6 +91,8 @@ InstrumentRack* getInstrumentRack(){ return m_pInstrumentRack; } QUndoStack* m_undoStack; + QTabWidget *pTab; + QSplitter *pSplitter; void setStatusBarMessage( const QString& msg, int msec = 0 ); @@ -105,8 +109,12 @@ void onDrumkitLoad( QString name ); void enableDestructiveRecMode(); + void cleanupTemporaryFiles(); + void addTemporaryFile( const QString& ); + public slots: void onEventQueueTimer(); + void currentTabChanged(int); private: static HydrogenApp *m_pInstance; ///< HydrogenApp instance @@ -114,6 +122,7 @@ #ifdef H2CORE_HAVE_LADSPA LadspaFXProperties *m_pLadspaFXProperties[MAX_FX]; #endif + MainForm *m_pMainForm; Mixer *m_pMixer; PatternEditorPanel* m_pPatternEditorPanel; @@ -128,6 +137,7 @@ Director *m_pDirector; QTimer *m_pEventQueueTimer; std::vector m_eventListeners; + QStringList temporaryFileList; // implement EngineListener interface void engineError(uint nErrorCode); diff -Nru hydrogen-0.9.6~beta1/src/gui/src/InstrumentEditor/InstrumentEditor.cpp hydrogen-0.9.6~beta2/src/gui/src/InstrumentEditor/InstrumentEditor.cpp --- hydrogen-0.9.6~beta1/src/gui/src/InstrumentEditor/InstrumentEditor.cpp 2011-12-04 16:40:41.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/InstrumentEditor/InstrumentEditor.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -847,7 +847,7 @@ void InstrumentEditor::rubberbandbpmchangeEvent() { - if( !Preferences::get_instance()->m_useTheRubberbandBpmChangeEvent /*&& Preferences::get_instance()->__usetimeline */){ + if( !Preferences::get_instance()->getRubberBandBatchMode() /*&& Preferences::get_instance()->__usetimeline */){ //we return also if time-line is activated. this wont work. // INFOLOG( "Tempo change: Recomputing rubberband samples is disabled" ); return; @@ -892,6 +892,6 @@ } } } - } + } } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/main.cpp hydrogen-0.9.6~beta2/src/gui/src/main.cpp --- hydrogen-0.9.6~beta1/src/gui/src/main.cpp 2011-11-04 23:20:37.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/main.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -130,6 +130,7 @@ defaultPalette.setColor( QPalette::HighlightedText, QColor( 255, 255, 255 ) ); pQApp->setPalette( defaultPalette ); + pQApp->setStyleSheet("QToolTip {padding: 1px; border: 1px solid rgb(199, 202, 204); background-color: rgb(227, 243, 252); color: rgb(64, 64, 66);}"); } @@ -411,13 +412,6 @@ MainForm *pMainForm = new MainForm( pQApp, songFilename ); pMainForm->show(); pSplash->finish( pMainForm ); - bool loadlist = HydrogenApp::get_instance()->getPlayListDialog()->loadListByFileName( playlistFilename ); - if( loadlist ){ - Playlist::get_instance()->setNextSongByNumber( 0 ); - }else - { - ___ERRORLOG ( "Error loading the playlist" ); - } if( ! playlistFilename.isEmpty() ){ bool loadlist = HydrogenApp::get_instance()->getPlayListDialog()->loadListByFileName( playlistFilename ); @@ -451,6 +445,7 @@ delete H2Core::Logger::get_instance(); if (H2Core::Object::count_active()) { + H2Core::Object::write_objects_map_to_cerr(); } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/MainForm.cpp hydrogen-0.9.6~beta2/src/gui/src/MainForm.cpp --- hydrogen-0.9.6~beta1/src/gui/src/MainForm.cpp 2011-12-04 16:23:30.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/MainForm.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -250,7 +250,7 @@ m_pFileMenu->addSeparator(); // ----- m_pFileMenu->addAction( trUtf8( "&Open" ), this, SLOT( action_file_open() ), QKeySequence( "Ctrl+O" ) ); - m_pFileMenu->addAction( trUtf8( "&Open Demo" ), this, SLOT( action_file_openDemo() ), QKeySequence( "Ctrl+D" ) ); + m_pFileMenu->addAction( trUtf8( "Open &Demo" ), this, SLOT( action_file_openDemo() ), QKeySequence( "Ctrl+D" ) ); m_pRecentFilesMenu = m_pFileMenu->addMenu( trUtf8( "Open &recent" ) ); @@ -281,7 +281,7 @@ //~ FILE menu // Undo menu - QMenu *m_pUndoMenu = m_pMenubar->addMenu( trUtf8( "Undo" ) ); + QMenu *m_pUndoMenu = m_pMenubar->addMenu( trUtf8( "&Undo" ) ); m_pUndoMenu->addAction( trUtf8( "Undo" ), this, SLOT( action_undo() ), QKeySequence( "Ctrl+Z" ) ); m_pUndoMenu->addAction( trUtf8( "Redo" ), this, SLOT( action_redo() ), QKeySequence( "Shift+Ctrl+Z" ) ); m_pUndoMenu->addAction( trUtf8( "Undo history" ), this, SLOT( openUndoStack() ), QKeySequence( "" ) ); @@ -300,16 +300,32 @@ // Tools menu QMenu *m_pToolsMenu = m_pMenubar->addMenu( trUtf8( "&Tools" )); -// if ( Preferences::get_instance()->getInterfaceMode() == Preferences::SINGLE_PANED ) { -// m_pWindowMenu->addAction( trUtf8("Show song editor"), this, SLOT( action_window_showSongEditor() ), QKeySequence( "" ) ); -// } m_pToolsMenu->addAction( trUtf8("Playlist &editor"), this, SLOT( action_window_showPlaylistDialog() ), QKeySequence( "" ) ); m_pToolsMenu->addAction( trUtf8("Director"), this, SLOT( action_window_show_DirectorWidget() ), QKeySequence( "Alt+D" ) ); m_pToolsMenu->addAction( trUtf8("&Mixer"), this, SLOT( action_window_showMixer() ), QKeySequence( "Alt+M" ) ); m_pToolsMenu->addAction( trUtf8("&Instrument Rack"), this, SLOT( action_window_showDrumkitManagerPanel() ), QKeySequence( "Alt+I" ) ); - m_pToolsMenu->addAction( trUtf8("&Preferences"), this, SLOT( showPreferencesDialog() ), QKeySequence( "Alt+P" ) ); + + + m_pInputModeMenu = m_pToolsMenu->addMenu( trUtf8( "Input mode" ) ); + m_pInstrumentAction = m_pInputModeMenu->addAction( trUtf8( "Instrument" ), this, SLOT( action_toggle_input_mode()), QKeySequence( "Ctrl+Alt+I" ) ); + m_pInstrumentAction->setCheckable( true ); + + m_pDrumkitAction = m_pInputModeMenu->addAction( trUtf8( "Drumkit" ), this, SLOT( action_toggle_input_mode()), QKeySequence( "Ctrl+Alt+D" ) ); + m_pDrumkitAction->setCheckable( true ); + + if( Preferences::get_instance()->__playselectedinstrument ) + { + m_pInstrumentAction->setChecked( true ); + m_pDrumkitAction->setChecked (false ); + } else { + m_pInstrumentAction->setChecked( false ); + m_pDrumkitAction->setChecked (true ); + } + + + m_pToolsMenu->addAction( trUtf8("&Preferences"), this, SLOT( showPreferencesDialog() ), QKeySequence( "Alt+P" ) ); //~ Tools menu @@ -470,6 +486,7 @@ fd->setFilter( trUtf8("Hydrogen Song (*.h2song)") ); fd->setAcceptMode( QFileDialog::AcceptSave ); fd->setWindowTitle( trUtf8( "Save song" ) ); + fd->setSidebarUrls( fd->sidebarUrls() << QUrl::fromLocalFile( Filesystem::songs_dir() ) ); Song *song = Hydrogen::get_instance()->getSong(); QString defaultFilename; @@ -486,7 +503,7 @@ fd->selectFile( defaultFilename ); QString filename; - if (fd->exec() == QDialog::Accepted) { + if (fd->exec() == QDialog::Accepted) { filename = fd->selectedFiles().first(); } @@ -510,10 +527,10 @@ Song *song = Hydrogen::get_instance()->getSong(); QString filename = song->get_filename(); - if ( filename.isEmpty() ) { - // just in case! - return action_file_save_as(); - } + if ( filename.isEmpty() ) { + // just in case! + return action_file_save_as(); + } bool saved = false; saved = song->save( filename ); @@ -538,6 +555,19 @@ } +void MainForm::action_toggle_input_mode() +{ + if( !Preferences::get_instance()->__playselectedinstrument ) + { + Preferences::get_instance()->__playselectedinstrument = true; + m_pInstrumentAction->setChecked( true ); + m_pDrumkitAction->setChecked (false ); + } else { + Preferences::get_instance()->__playselectedinstrument = false; + m_pInstrumentAction->setChecked( false ); + m_pDrumkitAction->setChecked (true ); + } +} void MainForm::action_help_about() { @@ -579,6 +609,7 @@ fd->setAcceptMode ( QFileDialog::AcceptSave ); fd->setWindowTitle ( trUtf8 ( "Save Pattern as ..." ) ); fd->setDirectory ( dir ); + fd->setSidebarUrls( fd->sidebarUrls() << QUrl::fromLocalFile( Filesystem::patterns_dir() ) ); @@ -768,7 +799,6 @@ { bool isVisible = HydrogenApp::get_instance()->getMixer()->isVisible(); h2app->showMixer( !isVisible ); - qDebug()<< isVisible; } @@ -1257,7 +1287,6 @@ //int songnumber = 0; HydrogenApp* app = HydrogenApp::get_instance(); Hydrogen* engine = Hydrogen::get_instance(); - switch (k->key()) { case Qt::Key_Space: onPlayStopAccelEvent(); @@ -1293,7 +1322,17 @@ onSaveAccelEvent(); return TRUE; break; - +/* + case Qt::Key_T: + if( engine->getSong()->get_mode() == Song::PATTERN_MODE ){ + engine->getSong()->set_mode( Song::SONG_MODE); + } + else if ( engine->getSong()->get_mode() == Song::SONG_MODE ) { + engine->getSong()->set_mode( Song::PATTERN_MODE ); + } + return TRUE; + break; +*/ case Qt::Key_F5 : if( engine->m_PlayList.size() == 0) break; @@ -1469,9 +1508,6 @@ case 1: action_file_exit(); break; - case 3: - action_file_save(); - QMessageBox::information( this, "Hydrogen", trUtf8( "Sorry, the Hydrogen-Songfile is not saved properly in this Jack-Session! You have to repeat the \"Save-Session\" procedure from your Jack-Session-Manager.") ); } } @@ -1647,6 +1683,13 @@ h2app->m_undoStack->redo(); } +void MainForm::undoRedoActionEvent( int nEvent ){ + if(nEvent == 0) + h2app->m_undoStack->undo(); + else if(nEvent == 1) + h2app->m_undoStack->redo(); +} + bool MainForm::handleSelectNextPrevSongOnPlaylist( int step ) { int playlistSize= Hydrogen::get_instance()->m_PlayList.size(); diff -Nru hydrogen-0.9.6~beta1/src/gui/src/MainForm.h hydrogen-0.9.6~beta2/src/gui/src/MainForm.h --- hydrogen-0.9.6~beta1/src/gui/src/MainForm.h 2011-10-21 16:00:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/MainForm.h 2012-05-25 12:19:45.000000000 +0000 @@ -27,6 +27,7 @@ #include #include +#include #include "EventListener.h" @@ -55,6 +56,7 @@ virtual void errorEvent( int nErrorCode ); virtual void jacksessionEvent( int nValue); virtual void playlistLoadSongEvent(int nIndex); + virtual void undoRedoActionEvent( int nEvent ); static void usr1SignalHandler(int unused); @@ -65,7 +67,7 @@ void action_file_new(); void action_file_open(); void action_file_openDemo(); - void action_file_save(); + void action_file_save(); void action_file_save_as(); void action_file_openPattern(); void action_file_export_pattern_as(); @@ -112,6 +114,8 @@ void action_undo(); void action_redo(); + void action_toggle_input_mode(); + void handleSigUsr1(); private slots: @@ -130,6 +134,9 @@ void functionDeleteInstrument(int instrument); + QMenu *m_pInputModeMenu; + QAction *m_pInstrumentAction; + QAction *m_pDrumkitAction; QMenu *m_pRecentFilesMenu; QAction *m_pRecentFileAction0; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/Mixer/Mixer.cpp hydrogen-0.9.6~beta2/src/gui/src/Mixer/Mixer.cpp --- hydrogen-0.9.6~beta1/src/gui/src/Mixer/Mixer.cpp 2011-05-09 01:37:41.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/Mixer/Mixer.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -210,7 +210,28 @@ Hydrogen::get_instance()->setSelectedInstrumentNumber(nLine); } - +void Mixer::unmuteAll( bool findSelectedInstr ) +{ + if(findSelectedInstr) + unmuteAll( Hydrogen::get_instance()->getSelectedInstrumentNumber() ); + else + unmuteAll( 0 ); +} + +void Mixer::unmuteAll( int selectedInstrument ) +{ + Hydrogen *pEngine = Hydrogen::get_instance(); + Song *pSong = pEngine->getSong(); + InstrumentList *pInstrList = pSong->get_instrument_list(); + int nInstruments = pInstrList->size(); + for ( int i = 0; i < nInstruments; ++i ) { + m_pMixerLine[i]->setMuteClicked( false ); + m_pMixerLine[i]->setSoloClicked( false ); + pInstrList->get( i )->set_muted( false ); + } + // select first instrument after unmute all + Hydrogen::get_instance()->setSelectedInstrumentNumber(selectedInstrument); +} void Mixer::soloClicked(MixerLine* ref) { diff -Nru hydrogen-0.9.6~beta1/src/gui/src/Mixer/Mixer.h hydrogen-0.9.6~beta2/src/gui/src/Mixer/Mixer.h --- hydrogen-0.9.6~beta1/src/gui/src/Mixer/Mixer.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/Mixer/Mixer.h 2012-05-25 12:19:45.000000000 +0000 @@ -59,6 +59,8 @@ void noteOnClicked(MixerLine* ref); void noteOffClicked(MixerLine* ref); void muteClicked(MixerLine* ref); + void unmuteAll( bool findSelectedInstr); + void unmuteAll( int selectedInstr); void soloClicked(MixerLine* ref); void volumeChanged(MixerLine* ref); void panChanged(MixerLine* ref); diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/DrumPatternEditor.cpp hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/DrumPatternEditor.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/DrumPatternEditor.cpp 2011-07-21 20:13:49.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/DrumPatternEditor.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -46,8 +46,6 @@ #include #include -#include - using namespace std; using namespace H2Core; @@ -63,7 +61,6 @@ , m_pPattern( NULL ) , m_pPatternEditorPanel( panel ) { - //setAttribute(Qt::WA_NoBackground); setFocusPolicy(Qt::ClickFocus); m_nGridWidth = Preferences::get_instance()->getPatternEditorGridWidth(); @@ -166,7 +163,15 @@ return; } Instrument *pSelectedInstrument = pSong->get_instrument_list()->get( row ); - if (ev->button() == Qt::LeftButton ) { + + + if( ev->button() == Qt::LeftButton && (ev->modifiers() & Qt::ShiftModifier) ) + { + //shift + leftClick: add noteOff note + SE_addNoteRightClickAction *action = new SE_addNoteRightClickAction( nColumn, row, __selectedPatternNumber ); + HydrogenApp::get_instance()->m_undoStack->push( action ); + } + else if (ev->button() == Qt::LeftButton ) { H2Core::Note *pDraggedNote = m_pPattern->find_note( nColumn, nRealColumn, pSelectedInstrument ); @@ -178,6 +183,7 @@ Note::Key oldNoteKeyVal = Note::C; Note::Octave oldOctaveKeyVal = Note::P8; + bool noteExisted = false; if( pDraggedNote ){ oldLength = pDraggedNote->get_length(); oldVelocity = pDraggedNote->get_velocity(); @@ -186,8 +192,10 @@ oldLeadLag = pDraggedNote->get_lead_lag(); oldNoteKeyVal = pDraggedNote->get_key(); oldOctaveKeyVal = pDraggedNote->get_octave(); + noteExisted = true; } + SE_addNoteAction *action = new SE_addNoteAction( nColumn, row, __selectedPatternNumber, @@ -197,22 +205,17 @@ oldPan_R, oldLeadLag, oldNoteKeyVal, - oldOctaveKeyVal ); + oldOctaveKeyVal, + noteExisted, + Preferences::get_instance()->getHearNewNotes(), + false, + false); + HydrogenApp::get_instance()->m_undoStack->push( action ); - } else if (ev->button() == Qt::RightButton ) { + + } else if (ev->button() == Qt::RightButton ) { m_bRightBtnPressed = true; - // __rightclickedpattereditor - // 0 = note length - // 1 = note off" - // 2 = edit velocity - // 3 = edit pan - // 4 = edit lead lag - if ( Preferences::get_instance()->__rightclickedpattereditor == 1){ - SE_addNoteRightClickAction *action = new SE_addNoteRightClickAction( nColumn, row, __selectedPatternNumber ); - HydrogenApp::get_instance()->m_undoStack->push( action ); - return; - } - // AudioEngine::get_instance()->lock( RIGHT_HERE ); + m_pDraggedNote = m_pPattern->find_note( nColumn, nRealColumn, pSelectedInstrument, false ); // needed for undo note length __nRealColumn = nRealColumn; @@ -223,7 +226,6 @@ } else { __oldLength = -1; } - // AudioEngine::get_instance()->unlock(); } } @@ -236,7 +238,11 @@ float oldPan_R, float oldLeadLag, int oldNoteKeyVal, - int oldOctaveKeyVal ) + int oldOctaveKeyVal, + bool listen, + bool isMidi, + bool isInstrumentMode, + bool isNoteOff) { Hydrogen *pEngine = Hydrogen::get_instance(); @@ -252,45 +258,70 @@ Song *pSong = Hydrogen::get_instance()->getSong(); - int nInstruments = pSong->get_instrument_list()->size(); Instrument *pSelectedInstrument = pSong->get_instrument_list()->get( row ); m_bRightBtnPressed = false; - AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine + AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine - bool bNoteAlreadyExist = false; - Pattern::notes_t* notes = (Pattern::notes_t*)pPattern->get_notes(); - FOREACH_NOTE_IT_BOUND(notes,it,nColumn) { - Note *pNote = it->second; - assert( pNote ); - if ( pNote->get_instrument() == pSelectedInstrument ) { - // the note exists...remove it! - bNoteAlreadyExist = true; - delete pNote; - notes->erase( it ); - break; - } - } + bool bNoteAlreadyExist = false; + if(!isInstrumentMode){ + Pattern::notes_t* notes = (Pattern::notes_t*)pPattern->get_notes(); + FOREACH_NOTE_IT_BOUND(notes,it,nColumn) { + Note *pNote = it->second; + assert( pNote ); + if ( pNote->get_instrument() == pSelectedInstrument ) { + + // the note exists...remove it! + bNoteAlreadyExist = true; + delete pNote; + notes->erase( it ); + break; + } + } + } + else + { + Note* note = pPattern->find_note( nColumn, -1, pSelectedInstrument, (Note::Key)oldNoteKeyVal, (Note::Octave)oldOctaveKeyVal ); + if( note ) { + + // the note exists...remove it! + bNoteAlreadyExist = true; + m_pPattern->remove_note( note ); + delete note; + } + } - if ( bNoteAlreadyExist == false ) { + + if ( bNoteAlreadyExist == false ) { // create the new note - const unsigned nPosition = nColumn; - const float fVelocity = oldVelocity; - const float fPan_L = oldPan_L ; - const float fPan_R = oldPan_R; + unsigned nPosition = nColumn; + float fVelocity = oldVelocity; + float fPan_L = oldPan_L ; + float fPan_R = oldPan_R; int nLength = oldLength; + + if( isNoteOff ) + { + fVelocity = 0.0f; + fPan_L = 0.5f; + fPan_R = 0.5f; + nLength = 1; + } + const float fPitch = 0.0f; Note *pNote = new Note( pSelectedInstrument, nPosition, fVelocity, fPan_L, fPan_R, nLength, fPitch ); - pNote->set_note_off( false ); - pNote->set_lead_lag( oldLeadLag ); - pNote->set_key_octave( (Note::Key)oldNoteKeyVal, (Note::Octave)oldOctaveKeyVal ); + pNote->set_note_off( isNoteOff ); + if( !isNoteOff ) pNote->set_lead_lag( oldLeadLag ); + pNote->set_key_octave( (Note::Key)oldNoteKeyVal, (Note::Octave)oldOctaveKeyVal ); pPattern->insert_note( pNote ); - // hear note - Preferences *pref = Preferences::get_instance(); - if ( pref->getHearNewNotes() ) { + if(isMidi){ + pNote->set_just_recorded(true); + } + // hear note + if ( listen && !isNoteOff ) { Note *pNote2 = new Note( pSelectedInstrument, 0, fVelocity, fPan_L, fPan_R, nLength, fPitch); AudioEngine::get_instance()->get_sampler()->note_on(pNote2); } @@ -314,61 +345,6 @@ } -void DrumPatternEditor::addNoteRightClickAction( int nColumn, int row, int selectedPatternNumber ) -{ - - Hydrogen *pEngine = Hydrogen::get_instance(); - PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); - - H2Core::Pattern *pPattern; - if ( (selectedPatternNumber != -1) && ( (uint)selectedPatternNumber < pPatternList->size() ) ) { - pPattern = pPatternList->get( selectedPatternNumber ); - } - else { - pPattern = NULL; - } - - Song *pSong = Hydrogen::get_instance()->getSong(); - int nInstruments = pSong->get_instrument_list()->size(); - Instrument *pSelectedInstrument = pSong->get_instrument_list()->get( row ); - - - m_bRightBtnPressed = true; - m_pDraggedNote = NULL; - - AudioEngine::get_instance()->lock( RIGHT_HERE ); - - // create the new note - const unsigned nPosition = nColumn; - const float fVelocity = 0.0f; - const float fPan_L = 0.5f; - const float fPan_R = 0.5f; - const int nLength = 1; - const float fPitch = 0.0f; - Note *poffNote = new Note( pSelectedInstrument, nPosition, fVelocity, fPan_L, fPan_R, nLength, fPitch); - poffNote->set_note_off( true ); - pPattern->insert_note( poffNote ); - - pSong->__is_modified = true; - - AudioEngine::get_instance()->unlock(); - - // update the selected line - int nSelectedInstrument = Hydrogen::get_instance()->getSelectedInstrumentNumber(); - if (nSelectedInstrument != row) { - Hydrogen::get_instance()->setSelectedInstrumentNumber( row ); - } - else { - update( 0, 0, width(), height() ); - m_pPatternEditorPanel->getVelocityEditor()->updateEditor(); - m_pPatternEditorPanel->getPanEditor()->updateEditor(); - m_pPatternEditorPanel->getLeadLagEditor()->updateEditor(); - m_pPatternEditorPanel->getNoteKeyEditor()->updateEditor(); - m_pPatternEditorPanel->getPianoRollEditor()->updateEditor(); - } -} - - void DrumPatternEditor::mouseReleaseEvent(QMouseEvent *ev) { UNUSED( ev ); @@ -378,7 +354,7 @@ return; } - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 0 ) ) { + if ( m_bRightBtnPressed && m_pDraggedNote ) { if ( m_pDraggedNote->get_note_off() ) return; SE_editNoteLenghtAction *action = new SE_editNoteLenghtAction( m_pDraggedNote->get_position(), m_pDraggedNote->get_position(), __row, m_pDraggedNote->get_length(),__oldLength, __selectedPatternNumber); @@ -387,7 +363,7 @@ } -void DrumPatternEditor::editNoteLenghtAction( int nColumn, int nRealColumn, int row, int length, int selectedPatternNumber ) +void DrumPatternEditor::editNoteLengthAction( int nColumn, int nRealColumn, int row, int length, int selectedPatternNumber ) { Hydrogen *pEngine = Hydrogen::get_instance(); PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); @@ -401,7 +377,6 @@ Note *pDraggedNote; Song *pSong = pEngine->getSong(); - int nInstruments = pSong->get_instrument_list()->size(); Instrument *pSelectedInstrument = pSong->get_instrument_list()->get( row ); AudioEngine::get_instance()->lock( RIGHT_HERE ); pDraggedNote = pPattern->find_note( nColumn, nRealColumn, pSelectedInstrument, false ); @@ -428,14 +403,8 @@ return; } - // __rightclickedpattereditor - // 0 = note length - // 1 = note off" - // 2 = edit velocity - // 3 = edit pan - // 4 = edit lead lag - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 0 ) ) { + if ( m_bRightBtnPressed && m_pDraggedNote ) { if ( m_pDraggedNote->get_note_off() ) return; int nTickColumn = getColumn( ev ); @@ -839,7 +808,6 @@ m_pPatternEditorPanel->getPanEditor()->updateEditor(); m_pPatternEditorPanel->getLeadLagEditor()->updateEditor(); m_pPatternEditorPanel->getNoteKeyEditor()->updateEditor(); - /// \todo [DrumPatternEditor::setResolution] aggiornare la risoluzione del Ruler in alto." } @@ -891,7 +859,6 @@ void DrumPatternEditor::selectedPatternChangedEvent() { - //cout << "selected pattern changed EVENT" << endl; updateEditor(); } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/DrumPatternEditor.h hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/DrumPatternEditor.h --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/DrumPatternEditor.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/DrumPatternEditor.h 2012-05-25 12:19:45.000000000 +0000 @@ -74,9 +74,12 @@ float oldPan_R, float oldLeadLag, int oldNoteKeyVal, - int oldOctaveKeyVal ); - void addNoteRightClickAction( int nColumn, int nRow, int selectedPatternNumber ); - void editNoteLenghtAction( int nColumn, int nRealColumn, int row, int length, int selectedPatternNumber ); + int oldOctaveKeyVal, + bool listen, + bool isMidi, + bool isInstrumentMode, + bool isNoteOff); + void editNoteLengthAction( int nColumn, int nRealColumn, int row, int length, int selectedPatternNumber ); void undoRedoAction( int column, QString mode, int nSelectedPatternNumber, diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/NotePropertiesRuler.cpp hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/NotePropertiesRuler.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/NotePropertiesRuler.cpp 2011-07-12 14:38:16.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/NotePropertiesRuler.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -149,7 +149,7 @@ sprintf( valueChar, "%#.2f", val); ( HydrogenApp::get_instance() )->setStatusBarMessage( QString("Set note velocity [%1]").arg( valueChar ), 2000 ); } - else if ( m_mode == PAN ){ + else if ( m_mode == PAN && !pNote->get_note_off() ){ float pan_L, pan_R; float val = (pNote->get_pan_r() - pNote->get_pan_l() + 0.5) + delta; @@ -263,7 +263,7 @@ __mode = "VELOCITY"; } - else if ( m_mode == PAN ){ + else if ( m_mode == PAN && !pNote->get_note_off() ){ __oldPan_L = pNote->get_pan_l(); __oldPan_R = pNote->get_pan_r(); @@ -348,7 +348,7 @@ sprintf( valueChar, "%#.2f", val); HydrogenApp::get_instance()->setStatusBarMessage( QString("Set note velocity [%1]").arg( valueChar ), 2000 ); } - else if ( m_mode == PAN ){ + else if ( m_mode == PAN && !pNote->get_note_off() ){ float pan_L, pan_R; if ( (ev->button() == Qt::MidButton) || (ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::LeftButton) ) { val = 0.5; @@ -762,7 +762,7 @@ FOREACH_NOTE_CST_IT_BOUND(notes,coit,pos) { Note *pNote = coit->second; assert( pNote ); - if ( pNote->get_instrument() != pSong->get_instrument_list()->get( nSelectedInstrument ) ) { + if ( pNote->get_note_off() || pNote->get_instrument() != pSong->get_instrument_list()->get( nSelectedInstrument ) ) { continue; } uint x_pos = 20 + pNote->get_position() * m_nGridWidth; @@ -1015,13 +1015,6 @@ p.setPen( QPen( res_1, 1, Qt::DashLine ) ); if (y == 40) p.setPen( QPen( QColor(0,0,0), 1, Qt::SolidLine ) ); p.drawLine(20, y, 20 + nNotes * m_nGridWidth, y); -/* if (y == 20 )p.drawText ( 5, y +2 , QString("O")); - if (y == 30 )p.drawText ( 6, y +2 , QString("c")); - if (y == 40 )p.drawText ( 7, y +2 , QString("t")); - if (y == 50 )p.drawText ( 5, y +2 , QString("a")); - if (y == 60 )p.drawText ( 6, y +2 , QString("v")); - if (y == 70 )p.drawText ( 6, y +2 , QString("e")); -*/ } for (unsigned y = 90; y < 210; y = y + 10 ) { @@ -1029,16 +1022,6 @@ if ( y == 100 ||y == 120 ||y == 140 ||y == 170 ||y == 190) p.setPen( QPen( QColor( 0, 0, 0 ), 7, Qt::SolidLine, Qt::FlatCap ) ); p.drawLine(20, y, 20 + nNotes * m_nGridWidth, y); -/* if (y == 100 )p.drawText ( 5, y +2 , QString("H")); - if (y == 110 )p.drawText ( 6, y +2 , QString("a")); - if (y == 120 )p.drawText ( 7, y +2 , QString("l")); - if (y == 130 )p.drawText ( 5, y +2 , QString("f")); - if (y == 150 )p.drawText ( 5, y +2 , QString("s")); - if (y == 160 )p.drawText ( 6, y +2 , QString("t")); - if (y == 170 )p.drawText ( 7, y +2 , QString("e")); - if (y == 180 )p.drawText ( 5, y +2 , QString("p")); - if (y == 190 )p.drawText ( 5, y +2 , QString("s")); -*/ } // vertical lines diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorInstrumentList.cpp hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorInstrumentList.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorInstrumentList.cpp 2011-07-12 14:38:16.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorInstrumentList.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -65,26 +65,26 @@ m_pMuteBtn = new ToggleButton( this, - "/patternEditor/btn_mute_on.png", - "/patternEditor/btn_mute_off.png", - "/patternEditor/btn_mute_off.png", - QSize( 9, 9 ) + "/mixerPanel/btn_mute_on.png", + "/mixerPanel/btn_mute_off.png", + "/mixerPanel/btn_mute_off.png", + QSize( 18, 13 ) ); - //m_pMuteBtn->setText( "M" ); - m_pMuteBtn->move( 155, 5 ); + m_pMuteBtn->move( 145, 5 ); m_pMuteBtn->setPressed(false); + m_pMuteBtn->setToolTip( trUtf8("Mute instrument") ); connect(m_pMuteBtn, SIGNAL(clicked(Button*)), this, SLOT(muteClicked())); m_pSoloBtn = new ToggleButton( this, - "/patternEditor/btn_solo_on.png", - "/patternEditor/btn_solo_off.png", - "/patternEditor/btn_solo_off.png", - QSize( 9, 9 ) + "/mixerPanel/btn_solo_on.png", + "/mixerPanel/btn_solo_off.png", + "/mixerPanel/btn_solo_off.png", + QSize( 18, 13 ) ); - //m_pSoloBtn->setText( "S" ); - m_pSoloBtn->move( 165, 5 ); + m_pSoloBtn->move( 163, 5 ); m_pSoloBtn->setPressed(false); + m_pSoloBtn->setToolTip( trUtf8("Solo") ); connect(m_pSoloBtn, SIGNAL(clicked(Button*)), this, SLOT(soloClicked())); diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorPanel.cpp hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorPanel.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorPanel.cpp 2011-07-08 16:42:02.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorPanel.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -50,8 +50,6 @@ #include -#include - void PatternEditorPanel::updateSLnameLabel( ) { @@ -119,7 +117,6 @@ } __pattern_size_combo->update(); connect(__pattern_size_combo, SIGNAL( valueChanged( QString ) ), this, SLOT( patternSizeChanged(QString) ) ); - //editor_top_hbox->addWidget(__pattern_size_combo); // GRID resolution @@ -140,11 +137,10 @@ __resolution_combo->update(); __resolution_combo->move( 121, 2 ); connect(__resolution_combo, SIGNAL(valueChanged(QString)), this, SLOT(gridResolutionChanged(QString))); - //editor_top_hbox->addWidget(__resolution_combo); PixmapWidget *pRec = new PixmapWidget( NULL ); - pRec->setFixedSize( 110, 20 ); + pRec->setFixedSize( 158, 20 ); pRec->setPixmap( "/patternEditor/background_rec-new.png" ); pRec->move( 0, 3 ); editor_top_hbox_2->addWidget( pRec ); @@ -173,10 +169,23 @@ QSize(15, 13) ); quantizeEventsBtn->move( 90, 3 ); - quantizeEventsBtn->setPressed( pPref->getQuantizeEvents()); + quantizeEventsBtn->setPressed( pPref->getQuantizeEvents()); quantizeEventsBtn->setToolTip( trUtf8( "Quantize keyboard/midi events to grid" ) ); connect( quantizeEventsBtn, SIGNAL(clicked(Button*)), this, SLOT( quantizeEventsBtnClick(Button*))); + // Editor mode + __show_drum_btn = new ToggleButton( + pRec, + "/patternEditor/btn_drum_piano_on.png", + "/patternEditor/btn_drum_piano_off.png", + "/patternEditor/btn_drum_piano_off.png", + QSize(17, 13) + ); + __show_drum_btn->move( 137, 3 ); + __show_drum_btn->setPressed( false ); + __show_drum_btn->setToolTip( trUtf8( "Show piano roll editor" ) ); + connect(__show_drum_btn, SIGNAL(clicked(Button*)), this, SLOT( showDrumEditorBtnClick(Button*))); + __recpredelete = new QComboBox( NULL ); __recpredelete->setFixedSize( 130, 20 ); __recpredelete->move( 2, 1 ); @@ -218,46 +227,6 @@ editor_top_hbox_2->addWidget( __recpostdelete ); connect( __recpostdelete, SIGNAL( currentIndexChanged( int ) ), this, SLOT( recPostDeleteSelect( int) ) ); - QComboBox *selInstrument = new QComboBox( NULL ); - selInstrument->setFixedSize( 100, 20 ); - selInstrument->move( 2, 1 ); - selInstrument->addItem ( QString( "drumset" )); - selInstrument->addItem ( QString( "instrument" )); - selInstrument->update(); - selInstrument->setToolTip( trUtf8( "Midi keyboard or computer keys play whole drumset or single instruments" ) ); - editor_top_hbox_2->addWidget( selInstrument ); - connect( selInstrument, SIGNAL( currentIndexChanged( QString ) ), this, SLOT( playselectedinstrument(QString) ) ); - - __rightclickSelection = new QComboBox( NULL ); - __rightclickSelection->setFixedSize( 100, 20 ); - __rightclickSelection->move( 2, 1 ); - __rightclickSelection->addItem ( QString( "note length" )); - __rightclickSelection->addItem ( QString( "note off" )); - __rightclickSelection->update(); - __rightclickSelection->setToolTip( trUtf8( "Right click into pattern editor add note-off-note or edit note-length, velocity or pan" ) ); - editor_top_hbox_2->addWidget( __rightclickSelection ); - connect( __rightclickSelection, SIGNAL( currentIndexChanged( QString ) ), this, SLOT( rightclickSelect(QString) ) ); - -//---------------------------experimental pianoroll-------------------------------------- -// show drum editor btn - __show_drum_btn = new ToggleButton( - NULL, - "/skin_btn_on.png", - "/skin_btn_off.png", - "/skin_btn_over.png", - QSize(60, 17), - true - ); - __show_drum_btn->setText( trUtf8("Piano") ); - __show_drum_btn->setPressed( false ); - __show_drum_btn->setToolTip( trUtf8( "Show piano roll editor" ) ); - connect(__show_drum_btn, SIGNAL(clicked(Button*)), this, SLOT( showDrumEditorBtnClick(Button*))); - editor_top_hbox_2->addWidget(__show_drum_btn); - -// hide the butten during develop on piano roll editor -//__show_drum_btn->hide(); - -//--------------------------------------------------------------------------------------- // zoom-in btn Button *zoom_in_btn = new Button( @@ -267,11 +236,8 @@ "/songEditor/btn_new_over.png", QSize(19, 13) ); -// zoom_in_btn->move( 51, 3 ); -// zoom_in_btn->setText("+"); zoom_in_btn->setToolTip( trUtf8( "Zoom in" ) ); connect(zoom_in_btn, SIGNAL(clicked(Button*)), this, SLOT( zoomInBtnClicked(Button*) ) ); - //editor_top_hbox_2->addWidget(zoom_in_btn); // zoom-out btn @@ -282,11 +248,8 @@ "/songEditor/btn_minus_over.png", QSize(19, 13) ); -// zoom_out_btn->move( 2, 3 ); - //zoom_out_btn->setText("-"); zoom_out_btn->setToolTip( trUtf8( "Zoom out" ) ); connect( zoom_out_btn, SIGNAL(clicked(Button*)), this, SLOT( zoomOutBtnClicked(Button*) ) ); - //editor_top_hbox_2->addWidget(zoom_out_btn); // End Editor TOP @@ -332,9 +295,6 @@ m_pPianoRollEditor = new PianoRollEditor( m_pPianoRollScrollView->viewport(), this ); m_pPianoRollScrollView->setWidget( m_pPianoRollEditor ); -// connect( m_pPianoRollScrollView->verticalScrollBar(), SIGNAL( valueChanged(int) ), this, SLOT( on_patternEditorScroll(int) ) ); - - m_pPianoRollScrollView->hide(); //~ EDITOR @@ -437,7 +397,6 @@ m_pPatternNameLbl = new QLabel( NULL ); m_pPatternNameLbl->setFont( boldFont ); m_pPatternNameLbl->setText( "pattern name label" ); - //m_pPatternNameLbl->setFixedWidth(200); m_pPatternNameLbl->setPalette(label_palette); @@ -677,7 +636,6 @@ m_pPattern = pPatternList->get( nSelectedPatternNumber ); QString sCurrentPatternName = m_pPattern->get_name(); this->setWindowTitle( ( trUtf8( "Pattern editor - %1").arg( sCurrentPatternName ) ) ); - //m_pNameLCD->setText( sCurrentPatternName ); m_pPatternNameLbl->setText( sCurrentPatternName ); // update pattern size combobox @@ -694,7 +652,6 @@ m_pPattern = NULL; this->setWindowTitle( ( trUtf8( "Pattern editor - %1").arg(QString("No pattern selected.")) ) ); - //m_pNameLCD->setText( trUtf8( "No pattern selected" ) ); m_pPatternNameLbl->setText( trUtf8( "No pattern selected" ) ); } @@ -754,12 +711,7 @@ QScrollArea *pScrollArea = m_pEditorScrollView; -// if ( m_pPianoRollScrollView->isVisible() ) { -// pScrollArea = m_pPianoRollScrollView; -// } -// else { - pScrollArea = m_pEditorScrollView; -// } + pScrollArea = m_pEditorScrollView; m_pPatternEditorHScrollBar->setMinimum( pScrollArea->horizontalScrollBar()->minimum() ); m_pPatternEditorHScrollBar->setMaximum( pScrollArea->horizontalScrollBar()->maximum() ); @@ -778,7 +730,6 @@ void PatternEditorPanel::showEvent ( QShowEvent *ev ) { UNUSED( ev ); -// m_pPatternEditorVScrollBar->setValue( m_pPatternEditorVScrollBar->maximum() ); } @@ -805,8 +756,7 @@ void PatternEditorPanel::showDrumEditorBtnClick(Button *ref) { UNUSED( ref ); - if ( !__show_drum_btn->isPressed() ){ - __show_drum_btn->setText( trUtf8("Piano") ); + if ( !__show_drum_btn->isPressed() ){ __show_drum_btn->setToolTip( trUtf8( "Show piano roll editor" ) ); m_pPianoRollScrollView->hide(); m_pEditorScrollView->show(); @@ -816,14 +766,10 @@ // force a re-sync of extern scrollbars resizeEvent( NULL ); - // - __rightclickSelection->clear(); - __rightclickSelection->addItem ( QString( "note length" )); - __rightclickSelection->addItem ( QString( "note off" )); + } else - { - __show_drum_btn->setText( trUtf8("Drum") ); + { __show_drum_btn->setToolTip( trUtf8( "Show drum editor" ) ); m_pPianoRollScrollView->show(); m_pPianoRollScrollView->verticalScrollBar()->setValue( 250 ); @@ -833,13 +779,6 @@ m_pPianoRollEditor->updateEditor(); // force an update // force a re-sync of extern scrollbars resizeEvent( NULL ); - - __rightclickSelection->clear(); - __rightclickSelection->addItem ( QString( "note length" )); - __rightclickSelection->addItem ( QString( "note off" )); - __rightclickSelection->addItem ( QString( "edit velocity" )); - __rightclickSelection->addItem ( QString( "edit pan" )); - __rightclickSelection->addItem ( QString( "edit lead lag" )); } } @@ -905,7 +844,6 @@ if ( nSelected > 0 && nSelected <= 32 ) { m_pPattern->set_length( nEighth * nSelected ); - //m_pPatternSizeLCD->setText( QString( "%1" ).arg( nSelected ) ); } else { ERRORLOG( QString("[patternSizeChanged] Unhandled case %1").arg( nSelected ) ); @@ -1007,6 +945,7 @@ m_pNoteNoteKeyScrollView->hide(); m_pNotePanScrollView->show(); + m_pNotePanEditor->updateEditor(); } else if ( text == trUtf8( "Lead and Lag" ) ) { @@ -1014,6 +953,7 @@ m_pNotePanScrollView->hide(); m_pNoteNoteKeyScrollView->hide(); m_pNoteLeadLagScrollView->show(); + m_pNoteLeadLagEditor->updateEditor(); } @@ -1035,51 +975,6 @@ } - -void PatternEditorPanel::playselectedinstrument( QString text ) -{ - if ( text == "drumset" ){ - Preferences::get_instance()->__playselectedinstrument = false; - }else - { - Preferences::get_instance()->__playselectedinstrument = true; - } -} - - -void PatternEditorPanel::rightclickSelect( QString text ) -{ -// __rightclickedpattereditor -// 0 = note length -// 1 = note off" -// 2 = edit velocity -// 3 = edit pan -// 4 = edit lead lag - - if ( text == "note length" ){ - Preferences::get_instance()->__rightclickedpattereditor = 0; - } - else if ( text == "note off" ) { - Preferences::get_instance()->__rightclickedpattereditor = 1; - } - else if ( text == "edit velocity" ) { - Preferences::get_instance()->__rightclickedpattereditor = 2; -// propertiesComboChanged( "Velocity" ); - __pPropertiesCombo->set_text("Velocity"); - } - else if ( text == "edit pan" ) { - Preferences::get_instance()->__rightclickedpattereditor = 3; -// propertiesComboChanged( "Pan" ); - __pPropertiesCombo->set_text("Pan"); - } - else if ( text == "edit lead lag" ) { - Preferences::get_instance()->__rightclickedpattereditor = 4; -// propertiesComboChanged( "Lead and Lag" ); - __pPropertiesCombo->set_text( "Lead and Lag" ); - } - -} - void PatternEditorPanel::recPreDeleteSelect( int index ) { Preferences::get_instance()->m_nRecPreDelete = index; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorPanel.h hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorPanel.h --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorPanel.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorPanel.h 2012-05-25 12:19:45.000000000 +0000 @@ -24,12 +24,11 @@ #ifndef PATTERN_EDITOR_PANEL_H #define PATTERN_EDITOR_PANEL_H -#include - #include #include "PianoRollEditor.h" #include "../EventListener.h" +#include "../widgets/LCDCombo.h" class Button; class ToggleButton; @@ -42,6 +41,8 @@ class PianoRollEditor; +enum patternEditorRightClickMode { VELOCITY_SELECTED, PAN_SELECTED, LEAD_LAG_SELECTED }; + namespace H2Core { class Pattern; @@ -66,6 +67,7 @@ NotePropertiesRuler* getNoteKeyEditor() { return m_pNoteNoteKeyEditor; } PatternEditorInstrumentList* getInstrumentList() { return m_pInstrumentList; } PianoRollEditor* getPianoRollEditor() { return m_pPianoRollEditor; } + QString getPropertiesComboText(){ return __pPropertiesCombo->getText(); } void updateSLnameLabel(); void displayorHidePrePostCB(); @@ -98,8 +100,6 @@ void moveDownBtnClicked(Button *); void moveUpBtnClicked(Button *); - void playselectedinstrument( QString text ); - void rightclickSelect( QString text ); void recPreDeleteSelect( int index ); void recPostDeleteSelect( int index ); @@ -119,7 +119,7 @@ // ~Editor top - // + //note properties combo LCDCombo * __pPropertiesCombo; // drum editor @@ -154,8 +154,6 @@ // note notekey editor QScrollArea* m_pNoteNoteKeyScrollView; NotePropertiesRuler *m_pNoteNoteKeyEditor; - - QScrollBar *m_pPatternEditorHScrollBar; QScrollBar *m_pPatternEditorVScrollBar; @@ -171,9 +169,6 @@ Button *sizeDropdownBtn; Button *resDropdownBtn; - - - QComboBox* __rightclickSelection; bool m_bEnablePatternResize; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorRuler.cpp hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorRuler.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorRuler.cpp 2011-07-08 16:42:02.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorRuler.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -20,20 +20,22 @@ * */ -#include -#include - #include #include #include #include using namespace H2Core; +#include +#include + + #include "PatternEditorRuler.h" #include "PatternEditorPanel.h" #include "../HydrogenApp.h" #include "../Skin.h" + const char* PatternEditorRuler::__class_name = "PatternEditorRuler"; PatternEditorRuler::PatternEditorRuler( QWidget* parent ) @@ -46,7 +48,6 @@ Preferences *pPref = Preferences::get_instance(); - //QColor backgroundColor(230, 230, 230); UIStyle *pStyle = pPref->getDefaultUIStyle(); QColor backgroundColor( pStyle->m_patternEditor_backgroundColor.getRed(), pStyle->m_patternEditor_backgroundColor.getGreen(), pStyle->m_patternEditor_backgroundColor.getBlue() ); @@ -58,7 +59,6 @@ m_nRulerHeight = 25; resize( m_nRulerWidth, m_nRulerHeight ); -// setFixedSize( size() ); bool ok = m_tickPosition.load( Skin::getImagePath() + "/patternEditor/tickPosition.png" ); if( ok == false ){ @@ -146,7 +146,6 @@ if (oldNTicks != m_nTicks) { // redraw all bRedrawAll = true; - //update( 0, 0, width(), height() ); } oldNTicks = m_nTicks; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorRuler.h hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorRuler.h --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PatternEditorRuler.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PatternEditorRuler.h 2012-05-25 12:19:45.000000000 +0000 @@ -24,7 +24,6 @@ #define PATTERN_EDITOR_RULER_H #include "../EventListener.h" - #include #include diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PianoRollEditor.cpp hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PianoRollEditor.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PianoRollEditor.cpp 2011-07-18 13:51:26.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PianoRollEditor.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -38,6 +38,7 @@ #include "../HydrogenApp.h" + const char* PianoRollEditor::__class_name = "PianoRollEditor"; PianoRollEditor::PianoRollEditor( QWidget *pParent, PatternEditorPanel *panel ) @@ -516,6 +517,13 @@ if (ev->button() == Qt::LeftButton ) { + if ( ev->modifiers() & Qt::ShiftModifier ){ + + SE_addPianoRollNoteOffAction *action = new SE_addPianoRollNoteOffAction( nColumn, pressedline, __selectedPatternNumber, nSelectedInstrumentnumber ); + HydrogenApp::get_instance()->m_undoStack->push( action ); + return; + } + unsigned nRealColumn = 0; if( ev->x() > 20 ) { nRealColumn = (ev->x() - 20) / static_cast(m_nGridWidth); @@ -567,21 +575,6 @@ nRealColumn = (ev->x() - 20) / static_cast(m_nGridWidth); } -// - // __rightclickedpattereditor - // 0 = note length - // 1 = note off" - // 2 = edit velocity - // 3 = edit pan - // 4 = edit lead lag - - if ( Preferences::get_instance()->__rightclickedpattereditor == 1){ - - SE_addNoteRightClickPianoRollAction *action = new SE_addNoteRightClickPianoRollAction( nColumn, pressedline, __selectedPatternNumber, nSelectedInstrumentnumber ); - HydrogenApp::get_instance()->m_undoStack->push( action ); - - } - // AudioEngine::get_instance()->lock( RIGHT_HERE ); @@ -622,130 +615,91 @@ float oldPan_R, float oldLeadLag, int oldNoteKeyVal, - int oldOctaveKeyVal ) + int oldOctaveKeyVal, + bool noteOff ) { - Hydrogen *pEngine = Hydrogen::get_instance(); - Song *pSong = pEngine->getSong(); - PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); - H2Core::Pattern *pPattern; - - Instrument *pSelectedInstrument = NULL; - pSelectedInstrument = pSong->get_instrument_list()->get( selectedinstrument ); - assert(pSelectedInstrument); - - if ( ( selectedPatternNumber != -1 ) && ( (uint)selectedPatternNumber < pPatternList->size() ) ) { - pPattern = pPatternList->get( selectedPatternNumber ); - } - else { - pPattern = NULL; - } - - Note::Octave pressedoctave = (Note::Octave)(3 - (pressedLine / 12 )); - Note::Key pressednotekey; - if ( pressedLine < 12 ){ - pressednotekey = (Note::Key)(11 - pressedLine); - } - else - { - pressednotekey = (Note::Key)(11 - pressedLine % 12); - } - - m_bRightBtnPressed = false; - - bool bNoteAlreadyExist = false; - AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine - Note* note = m_pPattern->find_note( nColumn, -1, pSelectedInstrument, pressednotekey, pressedoctave ); - if( note ) { - // the note exists...remove it! - bNoteAlreadyExist = true; - m_pPattern->remove_note( note ); - delete note; - } - - if ( bNoteAlreadyExist == false ) { - // create the new note - const unsigned nPosition = nColumn; - const float fVelocity = oldVelocity; - const float fPan_L = oldPan_L; - const float fPan_R = oldPan_R; - int nLength = oldLength; - const float fPitch = 0.0f; - Note *pNote = new Note( pSelectedInstrument, nPosition, fVelocity, fPan_L, fPan_R, nLength, fPitch ); - pNote->set_note_off( false ); - pNote->set_lead_lag( oldLeadLag ); - pNote->set_key_octave( pressednotekey, pressedoctave ); - pPattern->insert_note( pNote ); - // hear note - Preferences *pref = Preferences::get_instance(); - if ( pref->getHearNewNotes() ) { - Note *pNote2 = new Note( pSelectedInstrument, 0, fVelocity, fPan_L, fPan_R, nLength, fPitch); - pNote2->set_key_octave( pressednotekey, pressedoctave ); - AudioEngine::get_instance()->get_sampler()->note_on(pNote2); - } - } - pSong->__is_modified = true; - AudioEngine::get_instance()->unlock(); // unlock the audio engine - - updateEditor(); - m_pPatternEditorPanel->getVelocityEditor()->updateEditor(); - m_pPatternEditorPanel->getPanEditor()->updateEditor(); - m_pPatternEditorPanel->getLeadLagEditor()->updateEditor(); - m_pPatternEditorPanel->getNoteKeyEditor()->updateEditor(); - m_pPatternEditorPanel->getDrumPatternEditor()->updateEditor(); + Hydrogen *pEngine = Hydrogen::get_instance(); + Song *pSong = pEngine->getSong(); + PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); + H2Core::Pattern *pPattern; + + Instrument *pSelectedInstrument = NULL; + pSelectedInstrument = pSong->get_instrument_list()->get( selectedinstrument ); + assert(pSelectedInstrument); + + if ( ( selectedPatternNumber != -1 ) && ( (uint)selectedPatternNumber < pPatternList->size() ) ) { + pPattern = pPatternList->get( selectedPatternNumber ); + } + else { + pPattern = NULL; + } + + Note::Octave pressedoctave = (Note::Octave)(3 - (pressedLine / 12 )); + Note::Key pressednotekey; + if ( pressedLine < 12 ){ + pressednotekey = (Note::Key)(11 - pressedLine); + } + else + { + pressednotekey = (Note::Key)(11 - pressedLine % 12); + } + + m_bRightBtnPressed = false; + + bool bNoteAlreadyExist = false; + AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine + Note* note = m_pPattern->find_note( nColumn, -1, pSelectedInstrument, pressednotekey, pressedoctave ); + if( note ) { + // the note exists...remove it! + bNoteAlreadyExist = true; + m_pPattern->remove_note( note ); + delete note; + } + + if ( bNoteAlreadyExist == false ) { + // create the new note + unsigned nPosition = nColumn; + float fVelocity = oldVelocity; + float fPan_L = oldPan_L; + float fPan_R = oldPan_R; + int nLength = oldLength; + float fPitch = 0.0f; + + if(noteOff) + { + fVelocity = 0.0f; + fPan_L = 0.5f; + fPan_R = 0.5f; + nLength = 1; + fPitch = 0.0f; + } + + + Note *pNote = new Note( pSelectedInstrument, nPosition, fVelocity, fPan_L, fPan_R, nLength, fPitch ); + pNote->set_note_off( noteOff ); + if(! noteOff) pNote->set_lead_lag( oldLeadLag ); + pNote->set_key_octave( pressednotekey, pressedoctave ); + pPattern->insert_note( pNote ); + // hear note + Preferences *pref = Preferences::get_instance(); + if ( pref->getHearNewNotes() && !noteOff ) { + Note *pNote2 = new Note( pSelectedInstrument, 0, fVelocity, fPan_L, fPan_R, nLength, fPitch); + pNote2->set_key_octave( pressednotekey, pressedoctave ); + AudioEngine::get_instance()->get_sampler()->note_on(pNote2); + } + } + pSong->__is_modified = true; + AudioEngine::get_instance()->unlock(); // unlock the audio engine + + updateEditor(); + m_pPatternEditorPanel->getVelocityEditor()->updateEditor(); + m_pPatternEditorPanel->getPanEditor()->updateEditor(); + m_pPatternEditorPanel->getLeadLagEditor()->updateEditor(); + m_pPatternEditorPanel->getNoteKeyEditor()->updateEditor(); + m_pPatternEditorPanel->getDrumPatternEditor()->updateEditor(); } -void PianoRollEditor::addNoteRightClickAction( int nColumn, int pressedLine, int selectedPatternNumber, int selectedinstrument) -{ - Hydrogen *pEngine = Hydrogen::get_instance(); - Song *pSong = pEngine->getSong(); - PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); - H2Core::Pattern *pPattern; - - Instrument *pSelectedInstrument = NULL; - pSelectedInstrument = pSong->get_instrument_list()->get( selectedinstrument ); - assert(pSelectedInstrument); - - if ( ( selectedPatternNumber != -1 ) && ( (uint)selectedPatternNumber < pPatternList->size() ) ) { - pPattern = pPatternList->get( selectedPatternNumber ); - } - else { - pPattern = NULL; - } - - Note::Octave pressedoctave = (Note::Octave)(3 - (pressedLine / 12 )); - Note::Key pressednotekey; - if ( pressedLine < 12 ){ - pressednotekey = (Note::Key)(11 - pressedLine); - } - else - { - pressednotekey = (Note::Key)(11 - pressedLine % 12); - } - - AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine - // create the new note - const unsigned nPosition = nColumn; - const float fVelocity = 0.0f; - const float fPan_L = 0.5f; - const float fPan_R = 0.5f; - const int nLength = 1; - const float fPitch = 0.0f; - Note *poffNote = new Note( pSelectedInstrument, nPosition, fVelocity, fPan_L, fPan_R, nLength, fPitch); - poffNote->set_note_off( true ); - poffNote->set_key_octave( pressednotekey, pressedoctave ); - pPattern->insert_note( poffNote ); - - pSong->__is_modified = true; - AudioEngine::get_instance()->unlock(); // unlock the audio engine - - updateEditor(); - m_pPatternEditorPanel->getVelocityEditor()->updateEditor(); - m_pPatternEditorPanel->getPanEditor()->updateEditor(); - m_pPatternEditorPanel->getLeadLagEditor()->updateEditor(); - m_pPatternEditorPanel->getNoteKeyEditor()->updateEditor(); - m_pPatternEditorPanel->getDrumPatternEditor()->updateEditor(); -} @@ -760,14 +714,7 @@ return; } - // __rightclickedpattereditor - // 0 = note length - // 1 = note off" - // 2 = edit velocity - // 3 = edit pan - // 4 = edit lead lag - - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 0 ) ) { + if (m_bRightBtnPressed && m_pDraggedNote ) { if ( m_pDraggedNote->get_note_off() ) return; int nTickColumn = getColumn( ev ); @@ -799,8 +746,10 @@ m_pPatternEditorPanel->getNoteKeyEditor()->updateEditor(); } + QString selectedProperty = m_pPatternEditorPanel->getPropertiesComboText(); + //edit velocity - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 2 ) ) { + if (m_bRightBtnPressed && m_pDraggedNote && selectedProperty == trUtf8( "Velocity" ) ) { if ( m_pDraggedNote->get_note_off() ) return; AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine @@ -834,7 +783,7 @@ } //edit pan - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 3 ) ) { + if (m_bRightBtnPressed && m_pDraggedNote && selectedProperty == trUtf8( "Pan" ) ) { if ( m_pDraggedNote->get_note_off() ) return; AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine @@ -875,7 +824,7 @@ } //edit lead lag - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 4 ) ) { + if (m_bRightBtnPressed && m_pDraggedNote && selectedProperty == trUtf8( "Lead and Lag" )) { if ( m_pDraggedNote->get_note_off() ) return; AudioEngine::get_instance()->lock( RIGHT_HERE ); // lock the audio engine @@ -930,18 +879,20 @@ return; } - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor == 0 ) ) { + if ( m_bRightBtnPressed && m_pDraggedNote ) { if ( m_pDraggedNote->get_note_off() ) return; - SE_editNoteLenghtPianoRollAction *action = new SE_editNoteLenghtPianoRollAction( m_pDraggedNote->get_position(), m_pDraggedNote->get_position(), m_pDraggedNote->get_length(),__oldLength, __selectedPatternNumber, __selectedInstrumentnumber, __pressedLine ); - HydrogenApp::get_instance()->m_undoStack->push( action ); - return; - } - if (m_bRightBtnPressed && m_pDraggedNote && ( Preferences::get_instance()->__rightclickedpattereditor >=2 ) ) { - if ( m_pDraggedNote->get_note_off() ) return; - SE_editNotePropertiesPianoRollAction *action = new SE_editNotePropertiesPianoRollAction( m_pDraggedNote->get_position(), + if( m_pDraggedNote->get_length() != __oldLength ) + { + SE_editPianoRollNoteLengthAction *action = new SE_editPianoRollNoteLengthAction( m_pDraggedNote->get_position(), m_pDraggedNote->get_position(), m_pDraggedNote->get_length(),__oldLength, __selectedPatternNumber, __selectedInstrumentnumber, __pressedLine ); + HydrogenApp::get_instance()->m_undoStack->push( action ); + } + + + if( __velocity == __oldVelocity && __oldLeadLag == __leadLag && __oldPan_L == __pan_L && __oldPan_R == __pan_R ) return; + SE_editNotePropertiesPianoRollAction *action = new SE_editNotePropertiesPianoRollAction( m_pDraggedNote->get_position(), m_pDraggedNote->get_position(), __selectedPatternNumber, __selectedInstrumentnumber, @@ -954,12 +905,12 @@ __leadLag, __oldLeadLag, __pressedLine ); - HydrogenApp::get_instance()->m_undoStack->push( action ); + HydrogenApp::get_instance()->m_undoStack->push( action ); } } -void PianoRollEditor::editNoteLenghtAction( int nColumn, int nRealColumn, int length, int selectedPatternNumber, int nSelectedInstrumentnumber, int pressedline) +void PianoRollEditor::editNoteLengthAction( int nColumn, int nRealColumn, int length, int selectedPatternNumber, int nSelectedInstrumentnumber, int pressedline) { Hydrogen *pEngine = Hydrogen::get_instance(); diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PianoRollEditor.h hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PianoRollEditor.h --- hydrogen-0.9.6~beta1/src/gui/src/PatternEditor/PianoRollEditor.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PatternEditor/PianoRollEditor.h 2012-05-25 12:19:45.000000000 +0000 @@ -64,9 +64,9 @@ float oldPan_R, float oldLeadLag, int oldNoteKeyVal, - int oldOctaveKeyVal ); + int oldOctaveKeyVal, + bool noteOff); - void addNoteRightClickAction( int nColumn, int pressedLine, int selectedPatternNumber, int selectedInstrumentnumber); void editNotePropertiesAction( int nColumn, int nRealColumn, int selectedPatternNumber, @@ -76,7 +76,7 @@ float pan_R, float leadLag, int pressedLine ); - void editNoteLenghtAction( int nColumn, int nRealColumn, int length, int selectedPatternNumber, int nSelectedInstrumentnumber, int pressedLine ); + void editNoteLengthAction( int nColumn, int nRealColumn, int length, int selectedPatternNumber, int nSelectedInstrumentnumber, int pressedLine ); public slots: void updateEditor(); diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PlayerControl.cpp hydrogen-0.9.6~beta2/src/gui/src/PlayerControl.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PlayerControl.cpp 2011-11-04 22:40:50.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PlayerControl.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -114,6 +114,8 @@ m_pRecBtn->setToolTip( trUtf8("Record") ); connect(m_pRecBtn, SIGNAL(clicked(Button*)), this, SLOT(recBtnClicked(Button*))); connect(m_pRecBtn, SIGNAL(rightClicked(Button*)), this, SLOT(recBtnRightClicked(Button*))); + MidiAction* pAction = new MidiAction("RECORD_READY"); + m_pRecBtn->setAction( pAction ); // Record+delete button @@ -145,7 +147,7 @@ m_pPlayBtn->setPressed(false); m_pPlayBtn->setToolTip( trUtf8("Play/ Pause") ); connect(m_pPlayBtn, SIGNAL(clicked(Button*)), this, SLOT(playBtnClicked(Button*))); - MidiAction* pAction = new MidiAction("PLAY"); + pAction = new MidiAction("PLAY"); m_pPlayBtn->setAction( pAction ); @@ -186,53 +188,37 @@ m_pSongLoopBtn->move(310, 17); m_pSongLoopBtn->setToolTip( trUtf8("Loop song") ); connect( m_pSongLoopBtn, SIGNAL( clicked(Button*) ), this, SLOT( songLoopBtnClicked(Button*) ) ); -//~ CONTROLS -// MODE - PixmapWidget *pModePanel = new PixmapWidget( NULL ); - pModePanel->setFixedSize( 90, 43 ); - pModePanel->setPixmap( "/playerControlPanel/background_Mode.png" ); - hbox->addWidget( pModePanel ); + // Live mode button m_pLiveModeBtn = new ToggleButton( - pModePanel, + pControlsPanel, "/playerControlPanel/statusLED_on.png", "/playerControlPanel/statusLED_off.png", "/playerControlPanel/statusLED_off.png", - QSize(11, 9) + QSize(68, 9) ); - m_pLiveModeBtn->move(10, 4); + m_pLiveModeBtn->move(180, 5); m_pLiveModeBtn->setPressed(true); m_pLiveModeBtn->setToolTip( trUtf8("Pattern Mode") ); connect(m_pLiveModeBtn, SIGNAL(clicked(Button*)), this, SLOT(liveModeBtnClicked(Button*))); // Song mode button m_pSongModeBtn = new ToggleButton( - pModePanel, + pControlsPanel, "/playerControlPanel/statusLED_on.png", "/playerControlPanel/statusLED_off.png", "/playerControlPanel/statusLED_off.png", - QSize(11, 9) + QSize(68, 9) ); - m_pSongModeBtn->move(10, 15); + m_pSongModeBtn->move(253, 5); m_pSongModeBtn->setPressed(false); m_pSongModeBtn->setToolTip( trUtf8("Song Mode") ); connect(m_pSongModeBtn, SIGNAL(clicked(Button*)), this, SLOT(songModeBtnClicked(Button*))); - // Switch mode button - m_pSwitchModeBtn = new Button( - pModePanel, - "/playerControlPanel/btn_mode_on.png", - "/playerControlPanel/btn_mode_off.png", - "/playerControlPanel/btn_mode_over.png", - QSize(69, 13) - ); - m_pSwitchModeBtn->move(10, 26); - m_pSwitchModeBtn->setToolTip( trUtf8("Switch Song/ Pattern Mode") ); - connect(m_pSwitchModeBtn, SIGNAL(clicked(Button*)), this, SLOT(switchModeBtnClicked(Button*))); -//~ MODE +//~ CONTROLS // BC on off PixmapWidget *pControlsBBTBConoffPanel = new PixmapWidget( NULL ); @@ -372,7 +358,7 @@ ); m_pRubberBPMChange->move( 133, 3 ); m_pRubberBPMChange->setToolTip( trUtf8("Recalculate Rubberband modified samples if bpm will change") ); - m_pRubberBPMChange->setPressed(false); + m_pRubberBPMChange->setPressed( Preferences::get_instance()->getRubberBandBatchMode()); connect( m_pRubberBPMChange, SIGNAL( clicked( Button* ) ), this, SLOT(rubberbandButtonToggle( Button* ) ) ); QString program = Preferences::get_instance()->m_rubberBandCLIexecutable; //test the path. if test fails, no button @@ -393,7 +379,11 @@ QSize( 20, 13 ) ); m_pMetronomeBtn->move( 10, 26 ); + m_pMetronomeBtn->setToolTip( trUtf8("Switch metronome on/off") ); connect( m_pMetronomeBtn, SIGNAL( clicked( Button* ) ), this, SLOT(metronomeButtonClicked( Button* ) ) ); + pAction = new MidiAction("TOGGLE_METRONOME"); + m_pMetronomeBtn->setAction( pAction ); + //~ BPM @@ -757,32 +747,6 @@ -/// Switch mode -void PlayerControl::switchModeBtnClicked(Button* ref) -{ - UNUSED( ref ); - - Song *song = m_pEngine->getSong(); - - m_pEngine->sequencer_stop(); - m_pEngine->setPatternPos( 0 ); // from start - if( song->get_mode() == Song::PATTERN_MODE ) { - m_pEngine->getSong()->set_mode( Song::SONG_MODE ); - m_pSongModeBtn->setPressed(true); - m_pLiveModeBtn->setPressed(false); - (HydrogenApp::get_instance())->setStatusBarMessage(trUtf8("Song mode selected."), 5000); - } - else { - m_pEngine->getSong()->set_mode( Song::PATTERN_MODE ); - m_pSongModeBtn->setPressed(false); - m_pLiveModeBtn->setPressed(true); - (HydrogenApp::get_instance())->setStatusBarMessage(trUtf8("Pattern mode selected."), 5000); - } -} - - - - /// Set Song mode void PlayerControl::songModeBtnClicked(Button* ref) { @@ -871,12 +835,12 @@ Preferences *pPref = Preferences::get_instance(); if (m_pRubberBPMChange->isPressed()) { EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); - pPref->m_useTheRubberbandBpmChangeEvent = true; + pPref->setRubberBandBatchMode(true); (HydrogenApp::get_instance())->setScrollStatusBarMessage(trUtf8("Recalculate all samples using Rubberband ON"), 2000); } else { - pPref->m_useTheRubberbandBpmChangeEvent = false; + pPref->setRubberBandBatchMode(false); (HydrogenApp::get_instance())->setScrollStatusBarMessage(trUtf8("Recalculate all samples using Rubberband OFF"), 2000); } } @@ -1097,7 +1061,7 @@ } else if ( pRef == m_pShowInstrumentRackBtn ) { bool isVisible = pH2App->getInstrumentRack()->isVisible(); - pH2App->getInstrumentRack()->setHidden( isVisible ); + pH2App->showInstrumentPanel( isVisible ); } } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PlayerControl.h hydrogen-0.9.6~beta2/src/gui/src/PlayerControl.h --- hydrogen-0.9.6~beta1/src/gui/src/PlayerControl.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PlayerControl.h 2012-05-25 12:19:45.000000000 +0000 @@ -98,8 +98,7 @@ void stopBtnClicked(Button* ref); void updatePlayerControl(); void songModeBtnClicked(Button* ref); - void liveModeBtnClicked(Button* ref); - void switchModeBtnClicked(Button* ref); + void liveModeBtnClicked(Button* ref); void jackTransportBtnClicked(Button* ref); //jack time master void jackMasterBtnClicked(Button* ref); @@ -141,8 +140,7 @@ ToggleButton *m_pSongLoopBtn; ToggleButton *m_pSongModeBtn; - ToggleButton *m_pLiveModeBtn; - Button *m_pSwitchModeBtn; + ToggleButton *m_pLiveModeBtn; //beatcounter ToggleButton *m_pBConoffBtn; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PreferencesDialog.cpp hydrogen-0.9.6~beta2/src/gui/src/PreferencesDialog.cpp --- hydrogen-0.9.6~beta1/src/gui/src/PreferencesDialog.cpp 2011-11-08 22:10:00.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PreferencesDialog.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -61,60 +61,56 @@ pPref->loadPreferences( false ); // reload user's preferences driverComboBox->clear(); - driverComboBox->addItem( "Auto" ); - driverComboBox->addItem( "JACK" ); - driverComboBox->addItem( "ALSA" ); - driverComboBox->addItem( "OSS" ); + driverComboBox->addItem( "Auto" ); +#ifdef H2CORE_HAVE_JACK + driverComboBox->addItem( "Jack" ); +#endif +#ifdef H2CORE_HAVE_ALSA + driverComboBox->addItem( "Alsa" ); +#endif +#ifdef H2CORE_HAVE_OSS + driverComboBox->addItem( "Oss" ); +#endif +#ifdef H2CORE_HAVE_PORTAUDIO driverComboBox->addItem( "PortAudio" ); -#ifdef Q_OS_MACX +#endif +#ifdef H2CORE_HAVE_COREAUDIO driverComboBox->addItem( "CoreAudio" ); #endif - // Selected audio Driver - QString sAudioDriver = pPref->m_sAudioDriver; - if (sAudioDriver == "Auto") { - driverComboBox->setCurrentIndex(0); - } - else if (sAudioDriver == "Jack") { - driverComboBox->setCurrentIndex(1); - } - else if ( sAudioDriver == "Alsa" ) { - driverComboBox->setCurrentIndex(2); - } - else if ( sAudioDriver == "Oss" ) { - driverComboBox->setCurrentIndex(3); - } - else if ( sAudioDriver == "PortAudio" ) { - driverComboBox->setCurrentIndex(4); - } - else if ( sAudioDriver == "CoreAudio" ) { - driverComboBox->setCurrentIndex(5); - } - else { - ERRORLOG( "Unknown audio driver from preferences [" + sAudioDriver + "]" ); - } + + if( driverComboBox->findText(pPref->m_sAudioDriver) > -1){ + driverComboBox->setCurrentIndex(driverComboBox->findText(pPref->m_sAudioDriver)); + } + else + { + driverInfoLbl->setText("Select your Audio Driver"); + ERRORLOG( "Unknown midi input from preferences [" + pPref->m_sAudioDriver + "]" ); + } m_pMidiDriverComboBox->clear(); +#ifdef H2CORE_HAVE_ALSA m_pMidiDriverComboBox->addItem( "ALSA" ); +#endif +#ifdef H2CORE_HAVE_PORTMIDI m_pMidiDriverComboBox->addItem( "PortMidi" ); - m_pMidiDriverComboBox->addItem( "CoreMidi" ); - m_pMidiDriverComboBox->addItem( "JackMidi" ); +#endif +#ifdef H2CORE_HAVE_COREMIDI + m_pMidiDriverComboBox->addItem( "CoreMidi" ); +#endif +#ifdef H2CORE_HAVE_JACK + m_pMidiDriverComboBox->addItem( "JackMidi" ); +#endif - if ( pPref->m_sMidiDriver == "ALSA" ) { - m_pMidiDriverComboBox->setCurrentIndex(0); - } - else if ( pPref->m_sMidiDriver == "PortMidi" ) { - m_pMidiDriverComboBox->setCurrentIndex(1); - } - else if ( pPref->m_sMidiDriver == "CoreMidi" ) { - m_pMidiDriverComboBox->setCurrentIndex(2); - } - else if ( pPref->m_sMidiDriver == "JackMidi" ) { - m_pMidiDriverComboBox->setCurrentIndex(3); - } - else { - ERRORLOG( "Unknown midi input from preferences [" + pPref->m_sMidiDriver + "]" ); + + if( m_pMidiDriverComboBox->findText(pPref->m_sMidiDriver) > -1){ + m_pMidiDriverComboBox->setCurrentIndex(m_pMidiDriverComboBox->findText(pPref->m_sMidiDriver)); + } + else + { + driverInfoLbl->setText("Select your Midi Driver"); + ERRORLOG( "Unknown midi input from preferences [" + pPref->m_sMidiDriver + "]" ); } m_pIgnoreNoteOffCheckBox->setChecked( pPref->m_bMidiNoteOffIgnore ); @@ -130,7 +126,9 @@ maxVoicesTxt->setValue( pPref->m_nMaxNotes ); // JACK - trackOutsCheckBox->setChecked( pPref->m_bJackTrackOuts ); + trackOutsCheckBox->setChecked( pPref->m_bJackTrackOuts ); + connect(trackOutsCheckBox, SIGNAL(toggled(bool)), this, SLOT(toggleTrackOutsCheckBox( bool ))); + connectDefaultsCheckBox->setChecked( pPref->m_bJackConnectDefaults ); trackOutputComboBox->setCurrentIndex( pPref->m_nJackTrackOutputMode ); //~ JACK @@ -262,13 +260,6 @@ rubberbandLineEdit->hide(); #endif -#ifdef H2CORE_HAVE_JACKSESSION - useJackSessinStoreFiles->setVisible(true); - useJackSessinStoreFiles->setChecked(pPref->getJackSessionUseSessionDir()); -#else - useJackSessinStoreFiles->setVisible(false); -#endif - m_bNeedDriverRestart = false; connect(m_pMidiDriverComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT( onMidiDriverComboBoxIndexChanged(int) )); } @@ -338,7 +329,6 @@ } // JACK - pPref->m_bJackTrackOuts = trackOutsCheckBox->isChecked(); pPref->m_bJackConnectDefaults = connectDefaultsCheckBox->isChecked(); @@ -424,10 +414,6 @@ //path to rubberband pPref-> m_rubberBandCLIexecutable = rubberbandLineEdit->text(); -#ifdef H2CORE_HAVE_JACKSESSION - pPref->setJackSessionUseSessionDir(useJackSessinStoreFiles->isChecked()); -#endif - //check preferences if ( pPref->m_brestartLash == true ){ pPref->m_bsetLash = true ; @@ -520,7 +506,7 @@ trackOutsCheckBox->setEnabled( false ); connectDefaultsCheckBox->setEnabled(false); } - else if ( driverComboBox->currentText() == "JACK" ) { // JACK + else if ( driverComboBox->currentText() == "Jack" ) { // JACK info += trUtf8("Jack Audio Connection Kit Driver
    Low latency audio driver"); if ( !bJack_support ) { info += trUtf8("
    Not compiled"); @@ -533,7 +519,7 @@ connectDefaultsCheckBox->setEnabled(true); trackOutsCheckBox->setEnabled( true ); } - else if ( driverComboBox->currentText() == "ALSA" ) { // ALSA + else if ( driverComboBox->currentText() == "Alsa" ) { // ALSA info += trUtf8("ALSA Driver
    "); if ( !bAlsa_support ) { info += trUtf8("
    Not compiled"); @@ -722,3 +708,8 @@ m_bNeedDriverRestart = true; } +void PreferencesDialog::toggleTrackOutsCheckBox(bool toggled) +{ + Preferences::get_instance()->m_bJackTrackOuts = toggled; + m_bNeedDriverRestart = true; +} diff -Nru hydrogen-0.9.6~beta1/src/gui/src/PreferencesDialog.h hydrogen-0.9.6~beta2/src/gui/src/PreferencesDialog.h --- hydrogen-0.9.6~beta1/src/gui/src/PreferencesDialog.h 2011-09-12 11:54:45.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/PreferencesDialog.h 2012-05-25 12:19:45.000000000 +0000 @@ -53,6 +53,7 @@ void on_styleComboBox_activated( int index ); void on_useLashCheckbox_clicked(); void onMidiDriverComboBoxIndexChanged( int index ); + void toggleTrackOutsCheckBox(bool toggled); private: bool m_bNeedDriverRestart; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditor.cpp hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditor.cpp --- hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditor.cpp 2011-10-24 10:31:06.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditor.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -56,6 +56,15 @@ const char* SongEditor::__class_name = "SongEditor"; + +SongEditorGridRepresentationItem::SongEditorGridRepresentationItem(int x, int y, bool value) +{ + this->x = x; + this->y = y; + this->value = value; +} + + SongEditor::SongEditor( QWidget *parent ) : QWidget( parent ) , Object( __class_name ) @@ -71,8 +80,6 @@ Preferences *pref = Preferences::get_instance(); m_nMaxPatternSequence = pref->getMaxBars(); - - int m_nInitialWidth = 10 + m_nMaxPatternSequence * m_nGridWidth; int m_nInitialHeight = 10; @@ -142,7 +149,6 @@ if ( ev->x() < 10 ) { return; } - //WARNINGLOG( "editor-pressed" ); int nRow = ev->y() / m_nGridHeight; int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth; @@ -177,7 +183,6 @@ } if ( bOverExistingPattern ) { - qDebug() << "select over existing!!"; // MOVE PATTERNS // INFOLOG( "[mousePressEvent] Move patterns" ); m_bIsMoving = true; @@ -189,7 +194,6 @@ } else { // INFOLOG( "[mousePressEvent] Select patterns" ); - qDebug() << "select!!"; // select patterns m_bShowLasso = true; m_lasso.setCoords( ev->x(), ev->y(), ev->x(), ev->y() ); @@ -240,7 +244,6 @@ void SongEditor::addPattern( int nColumn , int nRow ) { - qDebug() << "add pattern!"; Hydrogen *pEngine = Hydrogen::get_instance(); Song *pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); @@ -277,7 +280,6 @@ void SongEditor::deletePattern( int nColumn , int nRow, unsigned nColumnIndex ) { - qDebug() << "delete pattern!"; Hydrogen *pEngine = Hydrogen::get_instance(); Song *pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); @@ -395,13 +397,45 @@ void SongEditor::mouseReleaseEvent( QMouseEvent *ev ) { UNUSED(ev); + if ( m_bIsMoving ) { // fine dello spostamento dei pattern - AudioEngine::get_instance()->lock( RIGHT_HERE ); // create the new patterns + + /* + * For the proper handling of undo events we have to make sure + * that the array m_movingCells does not include cells that are + * already existing. + * + * Example: A song consists of a sequence with the cells 0,1 and 3. + * Consider that we the two first cells 0 and 1 get moved one + * cell to the right (to 2,3). An undo action would now delete + * (2,3) for and re-create 0,1. Cell 3 got deleted now, but it existed + * before the first move operation. + */ + + SongEditorGridRepresentationItem* item; + m_existingCells.clear(); + for ( uint i = 0; i < m_movingCells.size(); i++ ) + { + QPoint cell = m_movingCells[ i ]; + + //looking for cell identified with (cell.x/cell.y) in the gridRepresentation + bool found = false; + foreach(item, gridRepresentation) + { + if(item->x == cell.x() && item->y == cell.y()) + { + found = true; + } + } + + if( found ){ + m_existingCells.push_back(cell); + } + } - SE_movePatternCellAction *action = new SE_movePatternCellAction( m_movingCells, m_selectedCells , m_bIsCtrlPressed); + SE_movePatternCellAction *action = new SE_movePatternCellAction( m_movingCells, m_selectedCells , m_existingCells, m_bIsCtrlPressed); HydrogenApp::get_instance()->m_undoStack->push( action ); - } setCursor( QCursor( Qt::ArrowCursor ) ); @@ -412,13 +446,25 @@ update(); } +/** + * @brief moves or copies a cell which represents a pattern + * @param movingCells Target cells for move/copy action + * @param selectedCells Currently selected cells for move/copy action + * @param existingCells Cells which are included in selected/movingCells but where existing before(import for undo). + * @param bIsCtrlPressed If ctrl is pressed, do copy instead of move + * @param undo Determine if this is an undo-operation + */ -void SongEditor::movePatternCellAction( std::vector movingCells, std::vector selectedCells, bool bIsCtrlPressed, bool undo ) +void SongEditor::movePatternCellAction( std::vector movingCells, std::vector selectedCells, std::vector existingCells, bool bIsCtrlPressed, bool undo ) { Hydrogen *pEngine = Hydrogen::get_instance(); PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); vector* pColumns = pEngine->getSong()->get_pattern_group_vector(); + + AudioEngine::get_instance()->lock( RIGHT_HERE ); + + //create the new patterns for ( uint i = 0; i < movingCells.size(); i++ ) { QPoint cell = movingCells[ i ]; if ( cell.x() < 0 || cell.y() < 0 || cell.y() >= (int)pPatternList->size() ) { @@ -441,12 +487,27 @@ pColumn->add( pPatternList->get( cell.y() ) ); } - if ( bIsCtrlPressed ) { // COPY - if ( undo ) - { + if ( bIsCtrlPressed) //Copy + { + if( undo ) + { // remove the old patterns for ( uint i = 0; i < selectedCells.size(); i++ ) { QPoint cell = selectedCells[ i ]; + + bool existing = false; + for ( uint i = 0; i < existingCells.size(); i++ ) { + QPoint existing_cell = existingCells[ i ]; + if(existing_cell.x() == cell.x() && existing_cell.y() == cell.y()) existing = true; + } + + //this cell existed before. Don't delete it! + if(existing){ + continue; + } + + + PatternList* pColumn = NULL; if ( cell.x() < (int)pColumns->size() ) { pColumn = (*pColumns)[ cell.x() ]; @@ -457,18 +518,7 @@ } pColumn->del(pPatternList->get( cell.y() ) ); } - for ( uint i = 0; i < movingCells.size(); i++ ) { - QPoint cell = movingCells[ i ]; - PatternList* pColumn = NULL; - if ( cell.x() < (int)pColumns->size() ) { - pColumn = (*pColumns)[ cell.x() ]; - } - else { - pColumn = new PatternList(); - pColumns->push_back( pColumn ); - } - pColumn->del(pPatternList->get( cell.y() ) ); - } + } } else { // MOVE @@ -476,15 +526,49 @@ for ( uint i = 0; i < selectedCells.size(); i++ ) { QPoint cell = selectedCells[ i ]; PatternList* pColumn = NULL; - if ( cell.x() < (int)pColumns->size() ) { - pColumn = (*pColumns)[ cell.x() ]; - } - else { - pColumn = new PatternList(); - pColumns->push_back( pColumn ); - } - pColumn->del(pPatternList->get( cell.y() ) ); - } + + /* + * Check first if pattern was present in movingCells. + * If it was, don't delete it! + */ + + bool moved = false; + for ( uint i = 0; i < movingCells.size(); i++ ) { + QPoint cell2 = movingCells[ i ]; + if( cell.x() == cell2.x() && cell.y() == cell2.y() ){ + moved = true; + } + } + + if( moved ) + { + continue; + } + + if( undo ) + { + bool existing = false; + for ( uint i = 0; i < existingCells.size(); i++ ) { + QPoint existing_cell = existingCells[ i ]; + if(existing_cell.x() == cell.x() && existing_cell.y() == cell.y()) existing = true; + } + + //this cell existed before. Don't delete it! + if(existing){ + continue; + } + } + + + if ( cell.x() < (int)pColumns->size() ) { + pColumn = (*pColumns)[ cell.x() ]; + } + else { + pColumn = new PatternList(); + pColumns->push_back( pColumn ); + } + pColumn->del(pPatternList->get( cell.y() ) ); + } } // remove the empty patternlist at the end of the song @@ -638,6 +722,14 @@ PatternList *patList = song->get_pattern_list(); vector* pColumns = song->get_pattern_group_vector(); uint listLength = patList->size(); + + //Drawing the pattern based on the gridRepresentation array + + while (!gridRepresentation.isEmpty()) + delete gridRepresentation.takeFirst(); + + + for (uint i = 0; i < pColumns->size(); i++) { PatternList* pColumn = (*pColumns)[ i ]; @@ -659,7 +751,9 @@ if (position == -1) { WARNINGLOG( QString("[drawSequence] position == -1, group = %1").arg( i ) ); } - drawPattern( i, position, false ); + //normal pattern + + gridRepresentation.append(new SongEditorGridRepresentationItem(i,position,false)); }//if for ( Pattern::virtual_patterns_cst_it_t it = pat->get_flattened_virtual_patterns()->begin(); it != pat->get_flattened_virtual_patterns()->end(); ++it) { @@ -668,13 +762,22 @@ if (position == -1) { WARNINGLOG( QString("[drawSequence] position == -1, group = %1").arg( i ) ); } - drawPattern( i, position, true ); + //virtual pattern + gridRepresentation.append(new SongEditorGridRepresentationItem(i,position,true)); drawnAsVirtual.insert(*it); } } } } + + //Draw the patterns according to the gridRepresentation + SongEditorGridRepresentationItem* s; + foreach(s, gridRepresentation) + { + drawPattern( s->x, s->y, s->value); + } + // Moving cells p.begin( m_pSequencePixmap ); // p.setRasterOp( Qt::XorROP ); @@ -724,7 +827,6 @@ int x = 10 + m_nGridWidth * pos; int y = m_nGridHeight * number; -// p.setPen( patternColor.light( 120 ) ); // willie - For the bevel - haven't yet figured how it's supposed to work... p.fillRect( x + 1, y + 3, m_nGridWidth - 1, m_nGridHeight - 5, patternColor ); } @@ -783,6 +885,7 @@ line = new QLineEdit( "Inline Pattern Name", this ); line->setFrame( false ); line->hide(); + line->setAcceptDrops( false ); connect( line, SIGNAL(editingFinished()), this, SLOT(inlineEditingFinished()) ); connect( line, SIGNAL(returnPressed()), this, SLOT(inlineEditingEntered()) ); @@ -795,13 +898,12 @@ m_playingPattern_off_Pixmap.load( Skin::getImagePath() + "/songEditor/playingPattern_off.png" ); m_pPatternPopup = new QMenu( this ); - //m_pPatternPopup->addAction( trUtf8("Edit"), this, SLOT( patternPopup_edit() ) );obsolete in >=0.9.4, because the patterneditor switch by clicking an each item to the corresponding pattern m_pPatternPopup->addAction( trUtf8("Copy"), this, SLOT( patternPopup_copy() ) ); m_pPatternPopup->addAction( trUtf8("Delete"), this, SLOT( patternPopup_delete() ) ); m_pPatternPopup->addAction( trUtf8("Fill/Clear ..."), this, SLOT( patternPopup_fill() ) ); m_pPatternPopup->addAction( trUtf8("Properties"), this, SLOT( patternPopup_properties() ) ); m_pPatternPopup->addAction( trUtf8("Load Pattern"), this, SLOT( patternPopup_load() ) ); - m_pPatternPopup->addAction( trUtf8("Save Pattern"), this, SLOT( patternPopup_save() ) ); + m_pPatternPopup->addAction( trUtf8("Save Pattern"), this, SLOT( patternPopup_save() ) ); m_pPatternPopup->addAction( trUtf8("Virtual Pattern"), this, SLOT( patternPopup_virtualPattern() ) ); HydrogenApp::get_instance()->addEventListener( this ); @@ -823,7 +925,7 @@ update(); ///here we check the timeline && m_pSong->get_mode() == Song::SONG_MODE Hydrogen *engine = Hydrogen::get_instance(); - if ( ( Preferences::get_instance()->__usetimeline ) && ( engine->getSong()->get_mode() == Song::SONG_MODE ) ){ + if ( ( Preferences::get_instance()->getUseTimelineBpm() ) && ( engine->getSong()->get_mode() == Song::SONG_MODE ) ){ for ( int i = 0; i < static_cast(engine->m_timelinevector.size()); i++){ if ( ( engine->m_timelinevector[i].m_htimelinebeat == engine->getPatternPos() ) && ( engine->getNewBpmJTM() != engine->m_timelinevector[i].m_htimelinebpm ) ){ @@ -852,19 +954,6 @@ } else { engine->setSelectedPatternNumber( row ); if (ev->button() == Qt::RightButton) { - /* - if ( song->getMode() == Song::PATTERN_MODE ) { - - PatternList *pCurrentPatternList = engine->getCurrentPatternList(); - if ( pCurrentPatternList->size() == 0 ) { - // nessun pattern e' attivo. seleziono subito questo. - pCurrentPatternList->add( patternList->get( row ) ); - } - else { - engine->setNextPattern( row ); - } - } - */ m_pPatternPopup->popup( QPoint( ev->globalX(), ev->globalY() ) ); } } @@ -880,32 +969,7 @@ void SongEditorPatternList::togglePattern( int row ) { Hydrogen *engine = Hydrogen::get_instance(); -/* Song *song = engine->getSong(); - PatternList *patternList = song->get_pattern_list();*/ - -// PatternList *pCurrentPatternList = engine->getCurrentPatternList(); - -// bool isPatternPlaying = false; engine->sequencer_setNextPattern( row, false, true ); - -// for ( uint i = 0; i < pCurrentPatternList->size(); ++i ) { -// if ( pCurrentPatternList->get( i ) == patternList->get( row ) ) { -// // the pattern is already playing, stop it! -// isPatternPlaying = true; -// break; -// } -// } -// -// if ( isPatternPlaying ) { -// //pCurrentPatternList->del( patternList->get( row ) ); -// engine->sequencer_setNextPattern( row, false, true ); // remove from the playing pattern list -// } -// else { -// // the pattern is not playing, add it to the list -// //pCurrentPatternList->add( patternList->get( row ) ); -// engine->sequencer_setNextPattern( row, true, false ); // add to the playing pattern list -// } - createBackground(); update(); } @@ -1129,7 +1193,7 @@ void SongEditorPatternList::patternPopup_load() { - + HydrogenApp *hydrogenApp = HydrogenApp::get_instance(); Hydrogen *engine = Hydrogen::get_instance(); int tmpselectedpatternpos = engine->getSelectedPatternNumber(); @@ -1158,9 +1222,11 @@ //create a unique sequencefilename time_t thetime; thetime = time(NULL); - QString sequenceFileName = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); - SE_loadPatternAction *action = new SE_loadPatternAction( filename, oldPatternName, sequenceFileName, tmpselectedpatternpos ); - HydrogenApp::get_instance()->m_undoStack->push( action ); + + QString sequenceFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); + SE_loadPatternAction *action = new SE_loadPatternAction( filename, oldPatternName, sequenceFilename, tmpselectedpatternpos ); + hydrogenApp->addTemporaryFile( sequenceFilename ); + hydrogenApp->m_undoStack->push( action ); @@ -1289,6 +1355,7 @@ { Hydrogen *pEngine = Hydrogen::get_instance(); + HydrogenApp *hydrogenApp = HydrogenApp::get_instance(); Song *song = pEngine->getSong(); PatternList *pSongPatternList = song->get_pattern_list(); int patternPosition = pEngine->getSelectedPatternNumber(); @@ -1296,13 +1363,15 @@ //create a unique sequencefilename time_t thetime; thetime = time(NULL); - QString sequenceFileName = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); + QString sequenceFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); //create a unique patternfilename - QString patternFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "PAT.xml" ); + QString patternFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "PAT.xml" ); - SE_deletePatternFromListAction *action = new SE_deletePatternFromListAction( patternFilename , sequenceFileName, patternPosition ); - HydrogenApp::get_instance()->m_undoStack->push( action ); + SE_deletePatternFromListAction *action = new SE_deletePatternFromListAction( patternFilename , sequenceFilename, patternPosition ); + hydrogenApp->addTemporaryFile( sequenceFilename ); + hydrogenApp->addTemporaryFile( patternFilename ); + hydrogenApp->m_undoStack->push( action ); } @@ -1436,6 +1505,7 @@ void SongEditorPatternList::patternPopup_copy() { Hydrogen *pEngine = Hydrogen::get_instance(); + HydrogenApp *hydrogenApp = HydrogenApp::get_instance(); Song *pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); int nSelectedPattern = pEngine->getSelectedPatternNumber(); @@ -1457,8 +1527,9 @@ int err =1; err = fileMng.savePattern( pSong, pEngine->getCurrentDrumkitname(), pPatternList->size() -1 , patternFilename, pNewPattern->get_name(), 4 ); - SE_copyPatternAction *action = new SE_copyPatternAction( patternFilename ,nSelectedPattern + 1 ); - HydrogenApp::get_instance()->m_undoStack->push( action ); + SE_copyPatternAction *action = new SE_copyPatternAction( patternFilename ,nSelectedPattern + 1 ); + hydrogenApp->addTemporaryFile( patternFilename ); + hydrogenApp->m_undoStack->push( action ); } //delete the tmp pattern @@ -1643,15 +1714,17 @@ //create a unique sequencefilename Song *song = Hydrogen::get_instance()->getSong(); Pattern *pat = song->get_pattern_list()->get( nTargetPattern ); + HydrogenApp *hydrogenApp = HydrogenApp::get_instance(); QString oldPatternName = pat->get_name(); time_t thetime; thetime = time(NULL); - QString sequenceFileName = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); - SE_loadPatternAction *action = new SE_loadPatternAction( sPatternName, oldPatternName, sequenceFileName, nTargetPattern ); - HydrogenApp::get_instance()->m_undoStack->push( action ); - + QString sequenceFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); + SE_loadPatternAction *action = new SE_loadPatternAction( sPatternName, oldPatternName, sequenceFilename, nTargetPattern ); + + hydrogenApp->addTemporaryFile( sequenceFilename); + hydrogenApp->m_undoStack->push( action ); } } @@ -1816,7 +1889,7 @@ //draw tempo content - if(pref->__usetimeline){ + if(pref->getUseTimelineBpm()){ p.setPen( textColor ); }else { @@ -1855,7 +1928,7 @@ // Right-click+drag int column = (ev->x() / m_nGridWidth); Preferences* pPref = Preferences::get_instance(); - if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) { + if ( column > (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) { pPref->setPunchOutPos(-1); return; } @@ -1876,7 +1949,7 @@ int column = (ev->x() / m_nGridWidth); m_bRightBtnPressed = false; - if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) { + if ( column > (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) { return; } @@ -1918,7 +1991,7 @@ pPref->setPunchOutPos(-1); update(); } - else if( ( ev->button() == Qt::LeftButton || ev->button() == Qt::RightButton ) && ev->y() <= 25 && Preferences::get_instance()->__usetimeline ){ + else if( ( ev->button() == Qt::LeftButton || ev->button() == Qt::RightButton ) && ev->y() <= 25 && Preferences::get_instance()->getUseTimelineBpm() ){ int column = (ev->x() / m_nGridWidth); SongEditorPanelBpmWidget dialog( this , column ); if (dialog.exec() == QDialog::Accepted) { diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditor.h hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditor.h --- hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditor.h 2011-01-17 23:08:21.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditor.h 2012-05-25 12:19:45.000000000 +0000 @@ -24,8 +24,10 @@ #define SONG_EDITOR_H #include +#include #include +#include #include #include "../EventListener.h" @@ -41,6 +43,16 @@ static const uint SONG_EDITOR_MIN_GRID_WIDTH = 8; static const uint SONG_EDITOR_MAX_GRID_WIDTH = 16; + +class SongEditorGridRepresentationItem +{ + public: + SongEditorGridRepresentationItem(int x, int y, bool value); + int x; + int y; + bool value; +}; + /// /// Song editor /// @@ -64,9 +76,12 @@ void deletePattern( int nColumn, int nRow, unsigned nColumnIndex); void clearThePatternSequenseVector( QString filename ); void updateEditorandSetTrue(); - void movePatternCellAction( std::vector movingCells, std::vector selectedCells, bool bIsCtrlPressed, bool undo); + void movePatternCellAction( std::vector movingCells, std::vector selectedCells, std::vector m_existingCells, bool bIsCtrlPressed, bool undo); private: + //holds a list for active patterns for each pattern + QList gridRepresentation; + unsigned m_nGridHeight; unsigned m_nGridWidth; unsigned m_nMaxPatternSequence; @@ -79,6 +94,8 @@ std::vector m_selectedCells; std::vector m_movingCells; + std::vector m_existingCells; + QPoint m_clickPoint; // Usato come riferimento per le operazioni di spostamento bool m_bShowLasso; QRect m_lasso; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditorPanelBpmWidget_UI.ui hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditorPanelBpmWidget_UI.ui --- hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditorPanelBpmWidget_UI.ui 2011-01-06 09:29:16.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditorPanelBpmWidget_UI.ui 2012-05-25 12:19:45.000000000 +0000 @@ -6,7 +6,7 @@ 0 0 - 195 + 198 151 diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditorPanel.cpp hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditorPanel.cpp --- hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditorPanel.cpp 2011-10-24 14:05:32.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditorPanel.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -67,7 +67,7 @@ m_pTimeLineToggleBtn->move( 133, 6 ); m_pTimeLineToggleBtn->setToolTip( trUtf8( "Enable time line edit") ); connect( m_pTimeLineToggleBtn, SIGNAL( clicked( Button* ) ), this, SLOT( timeLineBtnPressed(Button* ) ) ); - m_pTimeLineToggleBtn->setPressed( Preferences::get_instance()->__usetimeline ); + m_pTimeLineToggleBtn->setPressed( Preferences::get_instance()->getUseTimelineBpm() ); // clear sequence button @@ -446,7 +446,10 @@ thetime = time(NULL); QString filename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" ); SE_deletePatternSequenceAction *action = new SE_deletePatternSequenceAction( filename ); - HydrogenApp::get_instance()->m_undoStack->push( action ); + HydrogenApp *hydrogenApp = HydrogenApp::get_instance(); + + hydrogenApp->m_undoStack->push( action ); + hydrogenApp->addTemporaryFile( filename ); } @@ -511,12 +514,12 @@ void SongEditorPanel::timeLineBtnPressed( Button* pBtn ) { if( m_pTimeLineToggleBtn->isPressed() ){ - Preferences::get_instance()->__usetimeline = true; + Preferences::get_instance()->setUseTimelineBpm( true ); Hydrogen::get_instance()->setTimelineBpm(); } else { - Preferences::get_instance()->__usetimeline = false; + Preferences::get_instance()->setUseTimelineBpm( false ); } m_pPositionRuler->createBackground(); } @@ -571,4 +574,5 @@ { resyncExternalScrollBar(); m_pModeActionBtn->setPressed( Preferences::get_instance()->patternModePlaysSelected() ); + HydrogenApp::get_instance()->getSongEditorPanel()->updateAll(); } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditorPanelTagWidget_UI.ui hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditorPanelTagWidget_UI.ui --- hydrogen-0.9.6~beta1/src/gui/src/SongEditor/SongEditorPanelTagWidget_UI.ui 2011-01-06 09:29:16.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SongEditor/SongEditorPanelTagWidget_UI.ui 2012-05-25 12:19:45.000000000 +0000 @@ -6,8 +6,8 @@ 0 0 - 289 - 417 + 293 + 420 diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SoundLibrary/SoundLibraryImportDialog.cpp hydrogen-0.9.6~beta2/src/gui/src/SoundLibrary/SoundLibraryImportDialog.cpp --- hydrogen-0.9.6~beta1/src/gui/src/SoundLibrary/SoundLibraryImportDialog.cpp 2011-10-21 15:12:15.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SoundLibrary/SoundLibraryImportDialog.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -257,7 +257,7 @@ if ( sInfo.m_sType == "pattern" ) { H2Core::LocalFileMng mng; - std::vector patternList = mng.getAllPatternName(); + std::vector patternList = mng.getAllPatternNames(); for ( uint i = 0; i < patternList.size(); ++i ) { if ( patternList[ i ] == sName ) { return true; diff -Nru hydrogen-0.9.6~beta1/src/gui/src/SoundLibrary/SoundLibraryPanel.cpp hydrogen-0.9.6~beta2/src/gui/src/SoundLibrary/SoundLibraryPanel.cpp --- hydrogen-0.9.6~beta1/src/gui/src/SoundLibrary/SoundLibraryPanel.cpp 2011-05-18 21:27:38.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/SoundLibrary/SoundLibraryPanel.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -253,7 +253,6 @@ //this is the second step to push the mng.funktion std::vector allPatternDirList = mng.getallPatternList(); - std::vector patternNameList = mng.getAllPatternName(); std::vector allCategoryNameList = mng.getAllCategoriesFromPattern(); //now sorting via category @@ -266,7 +265,7 @@ for (uint i = 0; i < allPatternDirList.size(); ++i) { QString patternCategory = mng.getCategoryFromPatternName( allPatternDirList[i]); - if ( patternCategory == categoryName ){ + if ( patternCategory == categoryName || patternCategory.isEmpty() && categoryName == "No category" ){ QTreeWidgetItem* pPatternItem = new QTreeWidgetItem( pCategoryItem ); pPatternItem->setText( 0, mng.getPatternNameFromPatternDir( allPatternDirList[i] )); pPatternItem->setToolTip( 0, mng.getDrumkitNameForPattern( allPatternDirList[i] )); @@ -572,7 +571,7 @@ //if we delete the current loaded drumkit we can get truble with some empty pointers // TODO this check is really unsafe if ( item->text(0) == Hydrogen::get_instance()->getCurrentDrumkitname() ){ - QMessageBox::warning( this, "Hydrogen", QString( "You try to delet the current loaded drumkit.\nThis is not possible!") ); + QMessageBox::warning( this, "Hydrogen", QString( "It is not possible to delete the currently loaded drumkit.\nTo delete this drumkit first load another drumkit.") ); return; } diff -Nru hydrogen-0.9.6~beta1/src/gui/src/UI/about_dialog.ui hydrogen-0.9.6~beta2/src/gui/src/UI/about_dialog.ui --- hydrogen-0.9.6~beta1/src/gui/src/UI/about_dialog.ui 2011-11-29 23:07:08.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/UI/about_dialog.ui 2012-05-25 12:19:45.000000000 +0000 @@ -126,17 +126,365 @@ &Authors - + 10 - 0 - 501 + 10 + 511 241 - - ## + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">This program is distributed under the terms of the GPL v2.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> GNU GENERAL PUBLIC LICENSE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Version 2, June 1991</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Copyright (C) 1989, 1991 Free Software Foundation, Inc.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 675 Mass Ave, Cambridge, MA 02139, USA</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Everyone is permitted to copy and distribute verbatim copies</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> of this license document, but changing it is not allowed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Preamble</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> The licenses for most software are designed to take away your</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">freedom to share and change it. By contrast, the GNU General Public</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">License is intended to guarantee your freedom to share and change free</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">software--to make sure the software is free for all its users. This</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">General Public License applies to most of the Free Software</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Foundation's software and to any other program whose authors commit to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">using it. (Some other Free Software Foundation software is covered by</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the GNU Library General Public License instead.) You can apply it to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">your programs, too.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> When we speak of free software, we are referring to freedom, not</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">price. Our General Public Licenses are designed to make sure that you</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">have the freedom to distribute copies of free software (and charge for</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">this service if you wish), that you receive source code or can get it</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">if you want it, that you can change the software or use pieces of it</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">in new free programs; and that you know you can do these things.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> To protect your rights, we need to make restrictions that forbid</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">anyone to deny you these rights or to ask you to surrender the rights.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">These restrictions translate to certain responsibilities for you if you</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribute copies of the software, or if you modify it.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> For example, if you distribute copies of such a program, whether</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">gratis or for a fee, you must give the recipients all the rights that</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">you have. You must make sure that they, too, receive or can get the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">source code. And you must show them these terms so they know their</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">rights.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> We protect your rights with two steps: (1) copyright the software, and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">(2) offer you this license which gives you legal permission to copy,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribute and/or modify the software.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Also, for each author's protection and ours, we want to make certain</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">that everyone understands that there is no warranty for this free</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">software. If the software is modified by someone else and passed on, we</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">want its recipients to know that what they have is not the original, so</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">that any problems introduced by others will not reflect on the original</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">authors' reputations.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Finally, any free program is threatened constantly by software</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">patents. We wish to avoid the danger that redistributors of a free</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">program will individually obtain patent licenses, in effect making the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">program proprietary. To prevent this, we have made it clear that any</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">patent must be licensed for everyone's free use or not licensed at all.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> The precise terms and conditions for copying, distribution and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">modification follow.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> GNU GENERAL PUBLIC LICENSE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 0. This License applies to any program or other work which contains</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">a notice placed by the copyright holder saying it may be distributed</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">under the terms of this General Public License. The &quot;Program&quot;, below,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">refers to any such program or work, and a &quot;work based on the Program&quot;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">means either the Program or any derivative work under copyright law:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">that is to say, a work containing the Program or a portion of it,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">either verbatim or with modifications and/or translated into another</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">language. (Hereinafter, translation is included without limitation in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the term &quot;modification&quot;.) Each licensee is addressed as &quot;you&quot;.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Activities other than copying, distribution and modification are not</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">covered by this License; they are outside its scope. The act of</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">running the Program is not restricted, and the output from the Program</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">is covered only if its contents constitute a work based on the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Program (independent of having been made by running the Program).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Whether that is true depends on what the Program does.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 1. You may copy and distribute verbatim copies of the Program's</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">source code as you receive it, in any medium, provided that you</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">conspicuously and appropriately publish on each copy an appropriate</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">copyright notice and disclaimer of warranty; keep intact all the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">notices that refer to this License and to the absence of any warranty;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">and give any other recipients of the Program a copy of this License</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">along with the Program.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">You may charge a fee for the physical act of transferring a copy, and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">you may at your option offer warranty protection in exchange for a fee.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 2. You may modify your copy or copies of the Program or any portion</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">of it, thus forming a work based on the Program, and copy and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribute such modifications or work under the terms of Section 1</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">above, provided that you also meet all of these conditions:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> a) You must cause the modified files to carry prominent notices</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> stating that you changed the files and the date of any change.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> b) You must cause any work that you distribute or publish, that in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> whole or in part contains or is derived from the Program or any</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> part thereof, to be licensed as a whole at no charge to all third</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> parties under the terms of this License.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> c) If the modified program normally reads commands interactively</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> when run, you must cause it, when started running for such</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> interactive use in the most ordinary way, to print or display an</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> announcement including an appropriate copyright notice and a</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> notice that there is no warranty (or else, saying that you provide</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> a warranty) and that users may redistribute the program under</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> these conditions, and telling the user how to view a copy of this</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> License. (Exception: if the Program itself is interactive but</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> does not normally print such an announcement, your work based on</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> the Program is not required to print an announcement.)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">These requirements apply to the modified work as a whole. If</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">identifiable sections of that work are not derived from the Program,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">and can be reasonably considered independent and separate works in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">themselves, then this License, and its terms, do not apply to those</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">sections when you distribute them as separate works. But when you</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribute the same sections as part of a whole which is a work based</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">on the Program, the distribution of the whole must be on the terms of</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">this License, whose permissions for other licensees extend to the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">entire whole, and thus to each and every part regardless of who wrote it.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Thus, it is not the intent of this section to claim rights or contest</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">your rights to work written entirely by you; rather, the intent is to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">exercise the right to control the distribution of derivative or</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">collective works based on the Program.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">In addition, mere aggregation of another work not based on the Program</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">with the Program (or with a work based on the Program) on a volume of</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">a storage or distribution medium does not bring the other work under</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the scope of this License.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 3. You may copy and distribute the Program (or a work based on it,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">under Section 2) in object code or executable form under the terms of</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Sections 1 and 2 above provided that you also do one of the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> a) Accompany it with the complete corresponding machine-readable</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> source code, which must be distributed under the terms of Sections</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 1 and 2 above on a medium customarily used for software interchange; or,</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> b) Accompany it with a written offer, valid for at least three</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> years, to give any third party, for a charge no more than your</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> cost of physically performing source distribution, a complete</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> machine-readable copy of the corresponding source code, to be</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> distributed under the terms of Sections 1 and 2 above on a medium</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> customarily used for software interchange; or,</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> c) Accompany it with the information you received as to the offer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> to distribute corresponding source code. (This alternative is</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> allowed only for noncommercial distribution and only if you</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> received the program in object code or executable form with such</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> an offer, in accord with Subsection b above.)</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">The source code for a work means the preferred form of the work for</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">making modifications to it. For an executable work, complete source</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">code means all the source code for all modules it contains, plus any</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">associated interface definition files, plus the scripts used to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">control compilation and installation of the executable. However, as a</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">special exception, the source code distributed need not include</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">anything that is normally distributed (in either source or binary</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">form) with the major components (compiler, kernel, and so on) of the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">operating system on which the executable runs, unless that component</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">itself accompanies the executable.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">If distribution of executable or object code is made by offering</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">access to copy from a designated place, then offering equivalent</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">access to copy the source code from the same place counts as</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribution of the source code, even though third parties are not</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">compelled to copy the source along with the object code.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 4. You may not copy, modify, sublicense, or distribute the Program</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">except as expressly provided under this License. Any attempt</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">otherwise to copy, modify, sublicense or distribute the Program is</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">void, and will automatically terminate your rights under this License.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">However, parties who have received copies, or rights, from you under</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">this License will not have their licenses terminated so long as such</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">parties remain in full compliance.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 5. You are not required to accept this License, since you have not</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">signed it. However, nothing else grants you permission to modify or</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribute the Program or its derivative works. These actions are</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">prohibited by law if you do not accept this License. Therefore, by</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">modifying or distributing the Program (or any work based on the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Program), you indicate your acceptance of this License to do so, and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">all its terms and conditions for copying, distributing or modifying</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the Program or works based on it.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 6. Each time you redistribute the Program (or any work based on the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Program), the recipient automatically receives a license from the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">original licensor to copy, distribute or modify the Program subject to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">these terms and conditions. You may not impose any further</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">restrictions on the recipients' exercise of the rights granted herein.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">You are not responsible for enforcing compliance by third parties to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">this License.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 7. If, as a consequence of a court judgment or allegation of patent</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">infringement or for any other reason (not limited to patent issues),</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">conditions are imposed on you (whether by court order, agreement or</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">otherwise) that contradict the conditions of this License, they do not</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">excuse you from the conditions of this License. If you cannot</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">distribute so as to satisfy simultaneously your obligations under this</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">License and any other pertinent obligations, then as a consequence you</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">may not distribute the Program at all. For example, if a patent</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">license would not permit royalty-free redistribution of the Program by</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">all those who receive copies directly or indirectly through you, then</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the only way you could satisfy both it and this License would be to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">refrain entirely from distribution of the Program.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">If any portion of this section is held invalid or unenforceable under</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">any particular circumstance, the balance of the section is intended to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">apply and the section as a whole is intended to apply in other</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">circumstances.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">It is not the purpose of this section to induce you to infringe any</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">patents or other property right claims or to contest validity of any</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">such claims; this section has the sole purpose of protecting the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">integrity of the free software distribution system, which is</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">implemented by public license practices. Many people have made</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">generous contributions to the wide range of software distributed</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">through that system in reliance on consistent application of that</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">system; it is up to the author/donor to decide if he or she is willing</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">to distribute software through any other system and a licensee cannot</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">impose that choice.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">This section is intended to make thoroughly clear what is believed to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">be a consequence of the rest of this License.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 8. If the distribution and/or use of the Program is restricted in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">certain countries either by patents or by copyrighted interfaces, the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">original copyright holder who places the Program under this License</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">may add an explicit geographical distribution limitation excluding</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">those countries, so that distribution is permitted only in or among</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">countries not thus excluded. In such case, this License incorporates</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the limitation as if written in the body of this License.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 9. The Free Software Foundation may publish revised and/or new versions</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">of the General Public License from time to time. Such new versions will</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">be similar in spirit to the present version, but may differ in detail to</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">address new problems or concerns.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Each version is given a distinguishing version number. If the Program</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">specifies a version number of this License which applies to it and &quot;any</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">later version&quot;, you have the option of following the terms and conditions</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">either of that version or of any later version published by the Free</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Software Foundation. If the Program does not specify a version number of</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">this License, you may choose any version ever published by the Free Software</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Foundation.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 10. If you wish to incorporate parts of the Program into other free</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">programs whose distribution conditions are different, write to the author</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">to ask for permission. For software which is copyrighted by the Free</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Software Foundation, write to the Free Software Foundation; we sometimes</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">make exceptions for this. Our decision will be guided by the two goals</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">of preserving the free status of all derivatives of our free software and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">of promoting the sharing and reuse of software generally.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> NO WARRANTY</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">REPAIR OR CORRECTION.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">POSSIBILITY OF SUCH DAMAGES.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> END OF TERMS AND CONDITIONS</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> How to Apply These Terms to Your New Programs</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> If you develop a new program, and you want it to be of the greatest</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">possible use to the public, the best way to achieve this is to make it</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">free software which everyone can redistribute and change under these terms.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> To do so, attach the following notices to the program. It is safest</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">to attach them to the start of each source file to most effectively</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">convey the exclusion of warranty; and each file should have at least</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">the &quot;copyright&quot; line and a pointer to where the full notice is found.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> &lt;one line to give the program's name and a brief idea of what it does.&gt;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Copyright (C) 19yy &lt;name of author&gt;</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> This program is free software; you can redistribute it and/or modify</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> it under the terms of the GNU General Public License as published by</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> the Free Software Foundation; either version 2 of the License, or</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> (at your option) any later version.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> This program is distributed in the hope that it will be useful,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> but WITHOUT ANY WARRANTY; without even the implied warranty of</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> GNU General Public License for more details.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> You should have received a copy of the GNU General Public License</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> along with this program; if not, write to the Free Software</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Also add information on how to contact you by electronic and paper mail.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">If the program is interactive, make it output a short notice like this</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">when it starts in an interactive mode:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Gnomovision version 69, Copyright (C) 19yy name of author</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> This is free software, and you are welcome to redistribute it</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> under certain conditions; type `show c' for details.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">The hypothetical commands `show w' and `show c' should show the appropriate</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">parts of the General Public License. Of course, the commands you use may</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">be called something other than `show w' and `show c'; they could even be</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">mouse-clicks or menu items--whatever suits your program.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">You should also get your employer (if you work as a programmer) or your</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">school, if any, to sign a &quot;copyright disclaimer&quot; for the program, if</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">necessary. Here is a sample; alter the names:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Yoyodyne, Inc., hereby disclaims all copyright interest in the program</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> `Gnomovision' (which makes passes at compilers) written by James Hacker.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> &lt;signature of Ty Coon&gt;, 1 April 1989</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> Ty Coon, President of Vice</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">This General Public License does not permit incorporating your program into</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">proprietary programs. If your program is a subroutine library, you may</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">consider it more useful to permit linking proprietary applications with the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">library. If this is what you want to do, use the GNU Library General</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">Public License instead of this License.</span></p></body></html> @@ -160,7 +508,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;">This program is distributed under the terms of the GPL v2.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt; color:#ffffff;"> GNU GENERAL PUBLIC LICENSE</span></p> @@ -507,6 +855,10 @@ + layoutWidget + logoLabel + TabWidget3 + aboutTxt diff -Nru hydrogen-0.9.6~beta1/src/gui/src/UI/ExportSongDialog_UI.ui hydrogen-0.9.6~beta2/src/gui/src/UI/ExportSongDialog_UI.ui --- hydrogen-0.9.6~beta1/src/gui/src/UI/ExportSongDialog_UI.ui 2011-01-08 21:54:12.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/UI/ExportSongDialog_UI.ui 2012-05-25 12:19:45.000000000 +0000 @@ -6,8 +6,8 @@ 0 0 - 490 - 312 + 495 + 336 @@ -17,7 +17,7 @@ 20 - 260 + 290 461 28 @@ -86,7 +86,7 @@ 10 - 170 + 200 471 81 @@ -171,7 +171,10 @@ - true + false + + + @@ -414,6 +417,121 @@ + + + + 20 + 165 + 461 + 31 + + + + + + + + 200 + 16777215 + + + + + 0 + 0 + + + + Interpolation: + + + + + + + + 100 + 25 + + + + Choose type of interpolation methode + + + + Linear + + + + + Cosine + + + + + Third + + + + + Cubic + + + + + Hermite + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enable tempo changing + + + TimeLine BPM + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enable use of rubberband batch processor + + + Rubberbad Batch + + + + + diff -Nru hydrogen-0.9.6~beta1/src/gui/src/UI/PreferencesDialog_UI.ui hydrogen-0.9.6~beta2/src/gui/src/UI/PreferencesDialog_UI.ui --- hydrogen-0.9.6~beta1/src/gui/src/UI/PreferencesDialog_UI.ui 2011-10-28 19:49:39.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/UI/PreferencesDialog_UI.ui 2012-05-25 12:19:45.000000000 +0000 @@ -330,19 +330,6 @@ Alt+R - - - - 10 - 100 - 511 - 31 - - - - Save song files in Jack Session Directory (default on) - - diff -Nru hydrogen-0.9.6~beta1/src/gui/src/UndoActions.h hydrogen-0.9.6~beta2/src/gui/src/UndoActions.h --- hydrogen-0.9.6~beta1/src/gui/src/UndoActions.h 2011-11-30 09:11:46.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/UndoActions.h 2012-05-25 12:19:45.000000000 +0000 @@ -329,10 +329,11 @@ class SE_movePatternCellAction : public QUndoCommand { public: - SE_movePatternCellAction( std::vector movingCells, std::vector selectedCells, bool bIsCtrlPressed ){ + SE_movePatternCellAction( std::vector movingCells, std::vector selectedCells, std::vector existingCells, bool bIsCtrlPressed ){ setText( QString( "Move/copy selected cells" ) ); __selectedCells = selectedCells; __movingCells = movingCells; + __existingCells = existingCells; __bIsCtrlPressed = bIsCtrlPressed; } @@ -340,18 +341,19 @@ { //qDebug() << "move/copy selected cells undo"; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getSongEditorPanel()->getSongEditor()->movePatternCellAction( __selectedCells, __movingCells, __bIsCtrlPressed, true ); + h2app->getSongEditorPanel()->getSongEditor()->movePatternCellAction( __selectedCells, __movingCells, __existingCells, __bIsCtrlPressed, true ); } virtual void redo() { //qDebug() << "move/copy selected cells redo"; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getSongEditorPanel()->getSongEditor()->movePatternCellAction( __movingCells, __selectedCells, __bIsCtrlPressed, false ); + h2app->getSongEditorPanel()->getSongEditor()->movePatternCellAction( __movingCells, __selectedCells, __existingCells, __bIsCtrlPressed, false ); } private: std::vector __selectedCells; std::vector __movingCells; + std::vector __existingCells; bool __bIsCtrlPressed; }; @@ -478,9 +480,17 @@ float oldPan_R, float oldLeadLag, int oldNoteKeyVal, - int oldOctaveKeyVal ){ - setText( QString( "Add note ( %1, %2)" ).arg( nColumn ).arg( nRow ) ); - //setText("add Pattern"); + int oldOctaveKeyVal, + bool noteExisted, + bool listen, + bool isMidi, + bool isInstrumentMode){ + + if( noteExisted ){ + setText( QString( "Delete note ( %1, %2)" ).arg( nColumn ).arg( nRow ) ); + } else { + setText( QString( "Add note ( %1, %2)" ).arg( nColumn ).arg( nRow ) ); + } __nColumn = nColumn; __nRow = nRow; __selectedPatternNumber = selectedPatternNumber; @@ -491,11 +501,15 @@ __oldLeadLag = oldLeadLag; __oldNoteKeyVal = oldNoteKeyVal; __oldOctaveKeyVal = oldOctaveKeyVal; + __listen = listen; + __isMidi = isMidi; + __isInstrumentMode = isInstrumentMode; } virtual void undo() { - //qDebug() << "Add note Undo "; + //qDebug() << "Add note Undo "; HydrogenApp* h2app = HydrogenApp::get_instance(); + __isMidi = false; // undo is never a midi event. h2app->getPatternEditorPanel()->getDrumPatternEditor()->addOrDeleteNoteAction( __nColumn, __nRow, __selectedPatternNumber, @@ -505,11 +519,15 @@ __oldPan_R, __oldLeadLag, __oldNoteKeyVal, - __oldOctaveKeyVal ); + __oldOctaveKeyVal, + __listen, + __isMidi, + __isInstrumentMode, + false ); } virtual void redo() { - //qDebug() << "Add Note Redo " ; + //qDebug() << "Add Note Redo " ; HydrogenApp* h2app = HydrogenApp::get_instance(); h2app->getPatternEditorPanel()->getDrumPatternEditor()->addOrDeleteNoteAction( __nColumn, __nRow, @@ -520,7 +538,11 @@ __oldPan_R, __oldLeadLag, __oldNoteKeyVal, - __oldOctaveKeyVal ); + __oldOctaveKeyVal, + __listen, + __isMidi, + __isInstrumentMode, + false ); } private: int __nColumn; @@ -533,6 +555,9 @@ float __oldLeadLag; int __oldNoteKeyVal; int __oldOctaveKeyVal; + bool __listen; + bool __isMidi; + bool __isInstrumentMode; }; @@ -550,13 +575,13 @@ { //qDebug() << "Add off note Note Undo "; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getDrumPatternEditor()->addOrDeleteNoteAction( __nColumn, __nRow, __selectedPatternNumber, -1, 0.8f, 0.5f, 0.5f, 0.0, 0, 0 ); + h2app->getPatternEditorPanel()->getDrumPatternEditor()->addOrDeleteNoteAction( __nColumn, __nRow, __selectedPatternNumber, -1, 0.8f, 0.5f, 0.5f, 0.0, 0, 0, false, false, false, true); } virtual void redo() { //qDebug() << "Add off note Note Redo " ; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getDrumPatternEditor()->addNoteRightClickAction( __nColumn, __nRow, __selectedPatternNumber ); + h2app->getPatternEditorPanel()->getDrumPatternEditor()->addOrDeleteNoteAction( __nColumn, __nRow, __selectedPatternNumber, -1, 0.8f, 0.5f, 0.5f, 0.0, 0, 0, false, false, false, true); } private: int __nColumn; @@ -580,13 +605,13 @@ { //qDebug() << "Change note length Undo "; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getDrumPatternEditor()->editNoteLenghtAction( __nColumn, __nRealColumn, __row, __oldLength, __selectedPatternNumber ); + h2app->getPatternEditorPanel()->getDrumPatternEditor()->editNoteLengthAction( __nColumn, __nRealColumn, __row, __oldLength, __selectedPatternNumber ); } virtual void redo() { //qDebug() << "Change note length Redo " ; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getDrumPatternEditor()->editNoteLenghtAction( __nColumn, __nRealColumn, __row, __length, __selectedPatternNumber ); + h2app->getPatternEditorPanel()->getDrumPatternEditor()->editNoteLengthAction( __nColumn, __nRealColumn, __row, __length, __selectedPatternNumber ); } private: int __nColumn; @@ -878,7 +903,8 @@ __oldPan_R, __oldLeadLag, __oldNoteKeyVal, - __oldOctaveKeyVal ); + __oldOctaveKeyVal, + false ); } virtual void redo() { @@ -894,7 +920,8 @@ __oldPan_R, __oldLeadLag, __oldNoteKeyVal, - __oldOctaveKeyVal ); + __oldOctaveKeyVal, + false ); } private: int __nColumn; @@ -910,12 +937,11 @@ int __oldOctaveKeyVal; }; -class SE_addNoteRightClickPianoRollAction : public QUndoCommand +class SE_addPianoRollNoteOffAction : public QUndoCommand { public: - SE_addNoteRightClickPianoRollAction( int nColumn, int pressedLine, int selectedPatternNumber, int nSelectedInstrumentnumber ){ + SE_addPianoRollNoteOffAction( int nColumn, int pressedLine, int selectedPatternNumber, int nSelectedInstrumentnumber ){ setText( QString( "Add piano roll NOTE_OFF note ( %1, %2 )" ).arg( nColumn ).arg( pressedLine ) ); - //setText("add Pattern"); __nColumn = nColumn; __pressedLine = pressedLine; __selectedPatternNumber = selectedPatternNumber; @@ -925,13 +951,14 @@ { //qDebug() << "Add off note Note Undo "; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getPianoRollEditor()->addOrDeleteNoteAction( __nColumn, __pressedLine, __selectedPatternNumber, __nSelectedInstrumentnumber, -1, 0.8f, 0.5f, 0.5f, 0.0, 0, 0 ); + h2app->getPatternEditorPanel()->getPianoRollEditor()->addOrDeleteNoteAction( __nColumn, __pressedLine, __selectedPatternNumber, __nSelectedInstrumentnumber, -1, 0.8f, 0.5f, 0.5f, 0.0, 0, 0 , true); } virtual void redo() { //qDebug() << "Add off note Note Redo " ; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getPianoRollEditor()->addNoteRightClickAction( __nColumn, __pressedLine, __selectedPatternNumber, __nSelectedInstrumentnumber); + h2app->getPatternEditorPanel()->getPianoRollEditor()->addOrDeleteNoteAction( __nColumn, __pressedLine, __selectedPatternNumber, __nSelectedInstrumentnumber, -1, 0.8f, 0.5f, 0.5f, 0.0, 0, 0, true); + } private: int __nColumn; @@ -941,10 +968,10 @@ }; -class SE_editNoteLenghtPianoRollAction : public QUndoCommand +class SE_editPianoRollNoteLengthAction : public QUndoCommand { public: - SE_editNoteLenghtPianoRollAction( int nColumn, int nRealColumn, int length, int oldLength, int selectedPatternNumber, int nSelectedInstrumentnumber, int pressedLine){ + SE_editPianoRollNoteLengthAction( int nColumn, int nRealColumn, int length, int oldLength, int selectedPatternNumber, int nSelectedInstrumentnumber, int pressedLine){ setText( QString( "Change piano roll note length " ) ); __nColumn = nColumn; __nRealColumn = nRealColumn; @@ -958,13 +985,13 @@ { //qDebug() << "Change note length Piano Roll Undo "; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getPianoRollEditor()->editNoteLenghtAction( __nColumn, __nRealColumn, __oldLength, __selectedPatternNumber, __nSelectedInstrumentnumber, __pressedLine); + h2app->getPatternEditorPanel()->getPianoRollEditor()->editNoteLengthAction( __nColumn, __nRealColumn, __oldLength, __selectedPatternNumber, __nSelectedInstrumentnumber, __pressedLine); } virtual void redo() { //qDebug() << "Change note length Piano RollRedo " ; HydrogenApp* h2app = HydrogenApp::get_instance(); - h2app->getPatternEditorPanel()->getPianoRollEditor()->editNoteLenghtAction( __nColumn, + h2app->getPatternEditorPanel()->getPianoRollEditor()->editNoteLengthAction( __nColumn, __nRealColumn, __length, __selectedPatternNumber, diff -Nru hydrogen-0.9.6~beta1/src/gui/src/widgets/Button.cpp hydrogen-0.9.6~beta2/src/gui/src/widgets/Button.cpp --- hydrogen-0.9.6~beta1/src/gui/src/widgets/Button.cpp 2011-11-27 00:35:04.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/gui/src/widgets/Button.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -65,9 +65,7 @@ m_overPixmap.fill( QColor( 0, 180, 0 ) ); } - // default text font - m_textFont.setPointSize( 10 ); - m_textFont.setBold( true ); + this->setStyleSheet("font-size: 9px; font-weight: bold;"); } @@ -159,11 +157,6 @@ } } - - - - - void Button::enterEvent(QEvent *ev) { UNUSED( ev ); @@ -246,7 +239,7 @@ if ( !m_sText.isEmpty() ) { - painter.setFont( m_textFont ); + painter.setFont( m_textFont ); QColor shadow(150, 150, 150, 100); QColor text(10, 10, 10); @@ -284,7 +277,6 @@ ToggleButton::ToggleButton( QWidget *pParent, const QString& sOnImg, const QString& sOffImg, const QString& sOverImg, QSize size, bool use_skin_style ) : Button( pParent, sOnImg, sOffImg, sOverImg, size, use_skin_style ) { - } diff -Nru hydrogen-0.9.6~beta1/src/tests/xml.cpp hydrogen-0.9.6~beta2/src/tests/xml.cpp --- hydrogen-0.9.6~beta1/src/tests/xml.cpp 2011-07-22 07:34:28.000000000 +0000 +++ hydrogen-0.9.6~beta2/src/tests/xml.cpp 2012-05-25 12:19:45.000000000 +0000 @@ -1,4 +1,5 @@ +#include #include #include diff -Nru hydrogen-0.9.6~beta1/todo_undo_implementation hydrogen-0.9.6~beta2/todo_undo_implementation --- hydrogen-0.9.6~beta1/todo_undo_implementation 2011-01-16 08:46:14.000000000 +0000 +++ hydrogen-0.9.6~beta2/todo_undo_implementation 2012-05-25 12:19:45.000000000 +0000 @@ -25,6 +25,8 @@ + Edit note length Pattern Editor (right cklicking) | Done + Add/Remove note Piano Roll Editor | Done + Add/Remove noteoff note Piano Roll Editor | Done + + Add/Remove note via Midi | Done + + Destructive recording (Delete Notes) | Done + Edit note length Piano Roll Editor (right cklicking) | Done + Edit velocity Piano Roll Editor | Done + Edit pan Piano Roll Editor | Done diff -Nru hydrogen-0.9.6~beta1/tools/git hydrogen-0.9.6~beta2/tools/git --- hydrogen-0.9.6~beta1/tools/git 2011-01-12 07:26:26.000000000 +0000 +++ hydrogen-0.9.6~beta2/tools/git 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -#! /bin/bash - -ABSPATH=$(readlink -f $0) - -GIT_BASE=${GIT_BASE:-${ABSPATH%/*/*/*}} - -PRJ=hydrogen -SVN_URL=http://svn.assembla.com/svn/hydrogen -BRANCHES_TO_TRACK="trunk undo jeremyz" - -LOCAL_REPO=local -LOCAL_DIR=${GIT_BASE}/${PRJ} -SVN_CLONE_REPO=svn_clone -SVN_CLONE_DIR=${GIT_BASE}/${PRJ}_svn - -RED="\033[0;31m" -RESET="\033[0m" - -URL_COLOR="\033[0;34m" -LRC="\033[0;33m" # LOCAL REPO COLOR -LBC="\033[0;36m" # LOCAL BRANCH COLOR -SRC="\033[0;35m" # SVN CLONE REPO COLOR -SBC="\033[0;32m" # SVN CLONE BRANCH COLOR -DSBC="\033[0;37m" # DISTANT SVN BRANCH COLOR - -function error() { - echo -e " => ${RED}FAILURE${RESET}" && exit 1 -} - -function ask_ok() { - echo -n -e "$1${RESET}[${RED}Y${RESET}n] : " - read OK - if [ "$OK" = "" -o "$OK" = "y" -o "$OK" = "Y" ]; then - return 0 - fi - echo -e "${RED}abort${RESET}" && return 1 -} - -function create_svn_clone() { - echo -e "** clone from ${URL_COLOR}${SVN_URL}${RESET}" && cd $GIT_BASE && git svn clone ${SVN_URL} -T trunk -b branches -t tags ${PRJ}_svn || error - cd ${SVN_CLONE_DIR} - for branch in $BRANCHES_TO_TRACK; do - echo -e "** checkout ${DSBC}${branch}${RESET} in ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${branch}_svn${RESET}" && git checkout $branch -b ${branch}_svn || error - done - echo -e "** add ${LRC}${LOCAL_DIR}${RESET} as repo ${LRC}${LOCAL_REPO}${RESET}" && git remote add ${LOCAL_REPO} ${LOCAL_DIR} || error -} - -function create_local_repo() { - echo -e "** git init ${LRC}${LOCAL_DIR}${RESET}" && git init ${LOCAL_DIR}|| error - echo -e "** cd ${LRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error - echo -e "** add ${SRC}${SVN_CLONE_DIR}${RESET} as repo ${SRC}${SVN_CLONE_REPO}${RESET}" && git remote add ${SVN_CLONE_REPO} ${SVN_CLONE_DIR} || error - echo -e "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error - for branch in $BRANCHES_TO_TRACK; do - echo -e "** checkout ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${branch}_svn${RESET} to ${SBC}${branch}${RESET}" && git checkout ${SVN_CLONE_REPO}/${branch}_svn -b ${branch} || error - done -} - -function fetch_svn(){ - echo -e "** cd ${SRC}${SVN_CLONE_DIR}${RESET}" && cd ${SVN_CLONE_DIR} || error - echo -e "** fetch from ${URL_COLOR}${SVN_URL}${RESET}" && git svn fetch || error - BRANCHES=$(git branch | sed -e s/*//) - for branch in $BRANCHES; do - echo -e "** rebase ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${branch}${RESET}" && git checkout $branch && git svn rebase || error - done - echo -e "** cd ${SRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error - echo -e "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error -} - -function pull_from_clone() { - #echo -e "** cd ${SRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error - #echo -e "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error - #echo -e "** merge ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET} within ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET}" && git merge ${SVN_CLONE_REPO}/${SVN_CLONE_B} || error - echo -e "To do so :" - echo -e " ${LRC}- save your current work ${SRC}$ git stash save NAME${RESET}" - echo -e " ${LRC}- leave your current branch ${SRC}$ git checkout ANOTHER_BRANCH${RESET}" - echo -e " ${LRC}- delete your branch ${SRC}$ git branch -D ${LOCAL_B}${RESET}" - echo -e " ${LRC}- checkout your branch ${SRC}$ git checkout ${SVN_CLONE_REPO}/${LOCAL_B}_svn -b ${LOCAL_B}${RESET}" - echo -e " ${LRC}- apply your current work ${SRC}$ git stash pop/apply${RESET}" -} - -function push_to_clone() { - echo -e "** cd ${SRC}${SVN_CLONE_DIR}${RESET}" && cd ${SVN_CLONE_DIR} || error - echo -e "** checkout ${SBC}${SVN_CLONE_B}${RESET}" && git checkout ${SVN_CLONE_B} || error - echo -e "** fetch ${LRC}${LOCAL_REPO}${RESET}" && git fetch ${LOCAL_REPO} || error - echo -e "** rebase ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET} within ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET}" && git rebase ${LOCAL_REPO}/${LOCAL_B} || error - #git log --format="%H %an %s" $SVN_HEAD..$LOCAL_HEAD - echo -e "** cd ${SRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error - echo -e "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error -} - -function dcommit() { - echo -e "** cd ${SRC}${SVN_CLONE_DIR}${RESET}" && cd ${SVN_CLONE_DIR} || error - echo -e "** checkout ${SBC}${SVN_CLONE_B}${RESET}" && git checkout ${SVN_CLONE_B} || error - echo -e "** rebase ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET}" && git svn rebase || error - echo -e "** dcommit ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET} to ${URL_COLOR}${SVN_URL}${RESET}" && git svn dcommit -} - -if [ ! -d ${SVN_CLONE_DIR} ]; then - ask_ok "clone svn repository ${URL_COLOR}${SVN_URL}${RESET} to ${SRC}${SVN_CLONE_DIR}${RESET} " && create_svn_clone -fi -if [ ! -d ${LOCAL_DIR} ]; then - ask_ok "create local repository within ${LRC}${LOCAL_DIR}${RESET} " && create_local_repo -fi - -cd ${LOCAL_DIR} -LOCAL_B=$(git branch |grep '*' | gawk '{print $2;}') || error -LOCAL_HEAD=$(git show --format="%H" HEAD | head -n 1 | gawk '{print $1 }') || error -echo -e "** ${LRC}${LOCAL_REPO}${RESET} current branch is ${LBC}${LOCAL_B}${RESET} head ${RED}${LOCAL_HEAD}${RESET}" -cd ${SVN_CLONE_DIR} -SVN_CLONE_B=${LOCAL_B}_svn -SVN_HEAD=$(git show --format="%H" HEAD | head -n 1 | gawk '{print $1 }') || error -echo -e "** ${LRC}${SVN_CLONE_REPO}${RESET} corresponding branch is ${LBC}${SVN_CLONE_B}${RESET} head ${RED}${SVN_HEAD}${RESET}" -cd ${LOCAL_DIR} - -while [ 1 ]; do - echo -e "\nOptions :" - echo -e " # 1) ${RED}fetch svn${RESET} and update branches within ${SRC}${SVN_CLONE_DIR}${RESET}" - echo -e " # 2) ${RED}push${RESET} ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET} within ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET}" - echo -e " # 3) ${RED}push${RESET} ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET} to ${URL_COLOR}${SVN_URL}${RESET}" - echo -e " # 4) ${RED}pull${RESET} ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_CLONE_B}${RESET} within ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET}" - echo -e " # q) ${RED}QUIT${RESET}" - echo -n -e "\nyour choice : " - read CHOICE - echo "" - case $CHOICE in - q) - exit 0 - ;; - 1) - fetch_svn - ;; - 2) - push_to_clone - ;; - 3) - dcommit - ;; - 4) - pull_from_clone - ;; - esac -done