diff --git a/TODO.md b/TODO.md index 523d5e171..af6e0f6c3 100644 --- a/TODO.md +++ b/TODO.md @@ -4,11 +4,8 @@ # THE REAL TO-DO LIST -- Amiga's Period Modulation not working - Song is silent after playing an order after loop point - Select loaded instrument on open - rewrite because I want a setting... -- re-engineer volume handling? Sound Unit cries at me -- finish status view - finish auto-clone once you have done all of this (maybe not the first one) and merged the two or so pending pull requests, release 0.6.1 diff --git a/doc/2-interface/components.md b/doc/2-interface/components.md index 4ed6e6a44..695ecf1e4 100644 --- a/doc/2-interface/components.md +++ b/doc/2-interface/components.md @@ -21,7 +21,8 @@ the following keyboard shortcuts work while on a text field: these work similar to text fields, but you may only input numbers. -they also usually have `+` and `-` buttons which allow you to increase/decrease the amount when clicked (and rapidly do so when click-holding). +they also usually have `+` and `-` buttons which allow you to increase/decrease the value when clicked (and rapidly do so when holding). +additionally, Ctrl-clicking these buttons may increase/decrease the value by a coarse amount. ## sliders @@ -29,7 +30,8 @@ sliders are used for controlling values in a quick manner by being dragged. using the scroll wheel while holding Ctrl will change the slider's value by small amounts. -right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field for a short period of time, allowing you to input precise values. +right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field, allowing you to input precise values. +once you click away it will become a slider again. ## windows @@ -37,13 +39,13 @@ right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn i windows may be moved, collapsed, closed or even docked around the workspace. -to move a window, press and hold the mouse button while on title bar or any empty space on it. +to move a window, press and hold the left mouse button while on the title bar or any empty space on it. then drag your mouse, and release it to stop moving. to resize a window, drag the bottom right corner (marked by a triangular tab) or the borders. to collapse a window, click on the triangle in the title bar. -clicking again expands it. +clicking again expands the window. to close a window, click on the `X` at the top right corner, or select it from the "window" menu. diff --git a/doc/7-systems/amiga.md b/doc/7-systems/amiga.md index af6bfb67f..981edf771 100644 --- a/doc/7-systems/amiga.md +++ b/doc/7-systems/amiga.md @@ -6,6 +6,28 @@ in this very computer music trackers were born... imported MOD files use this chip, and will set A-4 tuning to 436. +## amplitude/period modulation + +Amiga has support for (rather primitive) amplitude and period (frequency) modulation. +however, nobody has used this feature as it is rather useless, not well-documented and works in a complicated way. + +Amiga sample playback is done by two chips: Paula (the one that you probably know) and Agnus (the one that actually feeds Paula with samples). +Agnus has several DMA (direct memory access) units which read from chip memory independent of the CPU. four of these DMA units are used for samples. + +when DMA is enabled, Paula requests sample data from Agnus, and then plays these samples back. +there's a catch though. since the data bus is 16-bit, Paula requests **two** 8-bit samples at once! this explains why: +- the sample length registers are in words rather than bytes (thereby allowing samples up to 131070 in length) +- the maximum playback rate (31250Hz PAL; ~31469Hz NTSC) is two times the HBlank rate (Agnus fetches samples on HBlank, around 15625Hz on PAL or ~15734Hz on NTSC) + +during normal sample playback, the first sample is output and then the second. afterwards, two more samples are fetched, and so on. + +now, when amplitude or period modulation are enabled, things work differently. +the channel is silenced, and the two 8-bit samples are **treated as a big-endian 16-bit number**, which is then written to the next channel's volume or period. + +in the case of amplitude modulation, only the second sample is significant because the volume register uses 7 bits (to represent 0 to 64 (65 to 127 are treated as 64)) and the other bits are ignored. + +in the case of period modulation, both samples are significant. the first sample is the upper byte, and the second is the lower byte. + ## effects - `10xx`: **toggle low-pass filter.** `0` turns it off and `1` turns it on. diff --git a/doc/7-systems/c219.md b/doc/7-systems/c219.md index 44d0cafd0..89cffc7d6 100644 --- a/doc/7-systems/c219.md +++ b/doc/7-systems/c219.md @@ -7,6 +7,13 @@ this chip features: - stereo soft panning - accepts either 8-bit PCM or proprietary 8-bit µ-law compressed PCM samples +## sample memory notice + +this chip is rather unique when it comes to sample memory. be sure to read this notice. + +the channels are in groups of four. a sample bank (128KB) may be selected for each group. +if a sample that is on a different bank plays in a group, the group is switched to that bank, and other channels will be silenced. + ## effects - `11xx`: **set noise mode.** diff --git a/doc/8-advanced/README.md b/doc/8-advanced/README.md index 97ecd6f2c..4a9512823 100644 --- a/doc/8-advanced/README.md +++ b/doc/8-advanced/README.md @@ -18,6 +18,7 @@ as listed in the "Window" menu: - [piano](piano.md) - [oscilloscope](osc.md) +- [oscilloscope (X-Y)](xyosc.md) - [oscilloscopes (per-channel)](chanosc.md) - [clock](clock.md) - [register view](regview.md) diff --git a/doc/8-advanced/channels.md b/doc/8-advanced/channels.md index a57698559..5b70f00dd 100644 --- a/doc/8-advanced/channels.md +++ b/doc/8-advanced/channels.md @@ -5,8 +5,8 @@ the "Channels" dialog allows manipulation of the song's channels. ![channels dialog](channels.png) each channel has the following options: -- **Visible**: uncheck the box to hide the channel from view. pattern data will be kept. +- **Visible**: uncheck the box to hide the channel from the pattern view. pattern data will be kept. - crossed-arrows button: click and drag to rearrange pattern data throughout the song. - - note: this does _not_ move channels around within a chip! it only affects pattern data. -- **Name** is the name displayed at the top of each channel in the tracker view. -- to the right of that is the abbreviation used above each channel in the order view. + - note: this does **not** move channels around! it only moves the channel's pattern data. +- **Name**: the name displayed at the top of each channel in the pattern view. +- the next setting is "short name", which is displayed in the orders view and/or when a channel is collapsed. diff --git a/doc/8-advanced/chanosc.md b/doc/8-advanced/chanosc.md index b811add81..8521c099f 100644 --- a/doc/8-advanced/chanosc.md +++ b/doc/8-advanced/chanosc.md @@ -1,25 +1,24 @@ # oscilloscope (per-channel) -the "Oscilloscope (per-channel)" dialog shows an individual oscilloscope for each channel during playback. +the "Oscilloscope (per-channel)" windows displays several oscilloscope views (one per channel). ![oscilloscope per-channel configuration view](chanosc.png) -right-clicking within the view will change it to the configuration view shown above: -- **Columns**: arranges oscilloscopes into this many columns. -- **Size (ms)**: sets what length of audio is visible in each oscilloscope. -- **Center waveform**: does its best to latch the waveform to the channel's note frequency and centers the display. +right-clicking the view will display the configuration view shown above: +- **Columns**: sets the amount of columns for the oscilloscope views. +- **Size (ms)**: sets how much of a channel's output is captured for the oscilloscope view. +- **Center waveform**: when enabled, the displayed waveforms will be centered using an auto-correlation algorithm. - **Automatic columns**: sets the number of columns based on the number of channels. - **Off**: use the Columns setting. - **Mode 1**: always fewer columns than rows. - **Mode 2**: bias slightly toward more columns. - **Mode 3**: always more columns than rows. -- **Amplitude**: scales amplitude for all oscilloscopes. -- **Gradient**: see below. -- the color selector sets the color for all waveforms. right-clicking on it pops up an option dialog: - - select between the square selector and the color wheel selector. - - **Alpha bar**: adds a transparency selector. -- the boxes below that are for selecting colors numerically by red-green-blue-alpha, hue-saturation-value-alpha, and HTML-style RGBA in hex. -- **Text format**: this string determins what text is shown in the top-left of each oscilloscope. it can be any text, and the following shortcodes will be replaced with information about the channel: +- **Amplitude**: scales amplitude for all oscilloscope views. +- **Gradient**: this allows you to use a gradient for determining the waveforms' colors instead of a single color. see the gradient section for more information. + - if this option is off, a color selector will be displayed. right-click on it for some options: + - select between the square selector and the color wheel selector. + - **Alpha bar**: display an opacity bar. +- **Text format**: this allows you to display some text on each oscilloscope view. the following codes may be used: - `%c`: channel name - `%C`: channel short name - `%d`: channel number (starting from 0) @@ -35,27 +34,32 @@ right-clicking within the view will change it to the configuration view shown ab - `%V`: volume (percentage) - `%b`: volume (hex) - `%%`: percent sign -- the OK button returns from options view to the oscilloscopes. + +click on OK to return to the main view. ## gradient ![oscilloscope per-channel gradient configuration view](chanosc-gradient.png) -in this mode, the color selector is replaced by a square field onto which circular "stops" can be placed. each stop adds a soft circle of color. the resulting image is used to look up the oscilloscope color as determined by each axis. +when enabling the Gradient setting, a gradient view is displayed in where circular "points" can be placed. +each point adds a color spot. +the resulting image is used to look up the waveform's color as determined by each axis. -- right-click to place a stop. -- left-click on a stop to change its color. the color selector is the same as above, with two additions: +- right-click to place a point. +- left-click on a point to change its color: + - a color picker is displayed, alongside two settings. - **Distance**: the size of the circle. - - **Spread**: the size of the solid center of the circle. increasing it fills more of the circle with the target color. + - **Spread**: the size of the solid center of the circle. increasing it fills more of the circle with the color. +- middle-click on a point to delete it. -- **Background**: sets background color for entire field. -- **X Axis**: determines what the horizontal maps to, from left to right. -- **Y Axis**: determines what the vertical maps to. from bottom to top. these can be set to the following: - - **None (0%)**: stays at the left or bottom. - - **None (50%)**: stays at the center. - - **None (100%)**: stays at the right or top. - - **Frequency**: changes color with note frequency. - - **Volume**: changes color with volume. - - **Channel**: changes color based on channel number. - - **Brightness**: currently does nothing. - - **Note Trigger**: changes color when a new note is played. +- **Background**: sets the gradient's background color. +- **X Axis**: determines what the horizontal axis maps to. +- **Y Axis**: determines what the vertical axis maps to. these can be set to the following: + - **None (0%)**: always left or bottom + - **None (50%)**: always center + - **None (100%)**: always right or top + - **Frequency**: changes color with frequency + - **Volume**: changes color with volume + - **Channel**: changes color based on channel number (first channel is 0% and last is 100%) + - **Brightness**: currently does nothing + - **Note Trigger**: changes color when a new note is played diff --git a/doc/8-advanced/chip-manager.md b/doc/8-advanced/chip-manager.md index bcfb6006d..72d8ff66a 100644 --- a/doc/8-advanced/chip-manager.md +++ b/doc/8-advanced/chip-manager.md @@ -1,15 +1,15 @@ # chip manager -the **chip manager** window does exactly what it says. +the **chip manager** window allows you to manage chips, including adding, changing, moving or removing them. ![chip manager](chip-manager.png) -**Preserve channel order**: make existing pattern data stay in place even when chips are rearranged. if turned off, pattern data will rearrange to match (the default, and usually the desired behavior). +**Preserve channel order**: make existing pattern data stay in place even when chips are rearranged. when turned off, pattern data will be arranged to match (the default, and usually desired behavior). -to move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to its left. +to move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to the left. -to replace a chip with a different one, click the **Change** button and select the replacement. +to replace a chip with a different one, click the **Change** button. this will display the chip selector. -to remove a chip entirely, click the ![X](chip-manager-remove.png) button. +to remove a chip, click the ![X](chip-manager-remove.png) button. -click a chip's name to open its options, where one can set clock rate, chip variant, and other specifics. \ No newline at end of file +click on a chip's name to open chip configuration. this allows you to change chip options, such as clock rate, chip type and so on. diff --git a/doc/8-advanced/comments.md b/doc/8-advanced/comments.md index ebb05d700..eb0fae144 100644 --- a/doc/8-advanced/comments.md +++ b/doc/8-advanced/comments.md @@ -4,4 +4,4 @@ comments, credits, or any arbitrary text may be entered here. it has no effect on the song. -there is no word wrap; long lines must be broken manually with the Enter key. +there is no word wrap; long lines must be broken manually with the Enter/Return key. diff --git a/doc/8-advanced/compat-flags.md b/doc/8-advanced/compat-flags.md index 6e050a410..e5ab02826 100644 --- a/doc/8-advanced/compat-flags.md +++ b/doc/8-advanced/compat-flags.md @@ -1,5 +1,5 @@ # compatibility flags -the **Compatibility Flags** window contains several tabs full of settings that change aspects of tracking and playback. a new Furnace song will have these disabled, while opening a DefleMask module, .mod, or earlier Furnace file will automatically set the appropriate options. +the **Compatibility Flags** window contains several tabs full of settings that change playback behavior. a new Furnace song will have these disabled, while opening a DefleMask module, .mod, or earlier Furnace file will automatically set the appropriate options. hovering over most options will bring up additional info about them. it is not recommended to change any of these, especially the ones in the DefleMask and Old Furnace sections. diff --git a/doc/8-advanced/grooves.md b/doc/8-advanced/grooves.md index 38775c5ab..3f566a7de 100644 --- a/doc/8-advanced/grooves.md +++ b/doc/8-advanced/grooves.md @@ -1,9 +1,6 @@ # grooves -grooves are macros for speed. - -a **groove** is the equivalent of repeating `0Fxx` commands on each row to get a cycle of speeds. for example, a groove of "6 4 5 3" makes the first row 6 ticks long, the next row 4 ticks, then 5, 3, 6, 4, 5, 3... - +a **groove** is the equivalent of repeating `0Fxx` effects on each row to get a cycle of speeds. for example, a groove of "6 4 5 3" makes the first row 6 ticks long, the next row 4 ticks, then 5, 3, 6, 4, 5, 3... ![groove](groove.png) @@ -13,18 +10,17 @@ to set the song's groove: - click again so it becomes "Groove". - enter a sequence of up to 16 speeds. - ![groove patterns](grooves.png) -the "Grooves" window is for entering preset groove patterns. -- the **`+`** button adds a new groove pattern; click in the pattern to edit it. +the "Grooves" window displays the list of groove patterns in the song. +- the **`+`** button adds a new groove pattern; click in the groove pattern to edit it. - the **`×`** buttons remove them. a single `09xx` command will switch to the matching numbered groove pattern. -## BPM +## tempo -this is a non-exhaustive list of grooves and their equivalent BPM. +this is a non-exhaustive list of grooves and their equivalent tempo in BPM. note: this table assumes a song's tick rate setting is left at its default value for the chosen engine speed: 60 for NTSC, or 50 for PAL. diff --git a/doc/8-advanced/osc.md b/doc/8-advanced/osc.md index db625e71c..145a26e39 100644 --- a/doc/8-advanced/osc.md +++ b/doc/8-advanced/osc.md @@ -1,9 +1,9 @@ # oscilloscope -the Oscilloscope shows the waveform of the mix of all currently playing sounds. +the Oscilloscope shows the audio output as a waveform. ![oscilloscope view](osc.png) -right-clicking on the oscilloscope toggles the adjustment sliders: -- waveform height zoom -- width of viewed audio (window size) in milliseconds. +right-clicking on the oscilloscope toggles adjustment sliders: +- waveform height (zoom) +- window size (how much of the output to display) in milliseconds. diff --git a/doc/8-advanced/xyosc.md b/doc/8-advanced/xyosc.md new file mode 100644 index 000000000..e03a1f945 --- /dev/null +++ b/doc/8-advanced/xyosc.md @@ -0,0 +1,19 @@ +# oscilloscope (X-Y) + +also called "vectorscope", this is similar to the normal oscilloscope in that it draws audio output as a waveform, but instead of being one-dimensional and going from left to right, it is plotted in two dimensions (usually X represents left output and Y represents right output). + +(TODO: image) + +right-clicking the X-Y oscilloscope window displays settings: +- **X Channel**: the output channel which will affect the X (horizontal) axis. default is 1 (left). + - **Invert**: flips the axis, therefore flipping the view horizontally. +- **Y Channel**: the output channel which will affect the Y (vertical) axis. default is 2 (right). + - **Invert**: flips the axis, therefore flipping the view vertically. +- **Zoom**: changes amplitude, making the plot bigger or smaller. +- **Samples**: the maximum number of samples to use for plotting. + - this setting may be replaced by another or removed in a future version. +- **Decay Time (ms)**: sets how long it takes for the points/lines to fade away. +- **Intensity**: changes the brightness of the dots/lines. +- **Line Thickness**: sets how thick lines are. + +click **OK** to return to the oscilloscope view. diff --git a/src/divasm/divasm.h b/src/divasm/divasm.h new file mode 100644 index 000000000..2846c98f8 --- /dev/null +++ b/src/divasm/divasm.h @@ -0,0 +1,30 @@ +struct DivASMResult { + int line, err; + DivASMResult(): + line(-1), + err(0) {} +}; + +struct DivASMFile { + String name; + SafeReader* data; +}; + +enum DivASMTarget { + DIV_ASM_TARGET_DUMMY=0, + DIV_ASM_TARGET_6502, + DIV_ASM_TARGET_SPC700 +}; + +class DivASM { + std::vector files; + SafeWriter* result; + + public: + DivASMResult getError(); + SafeWriter* assemble(String name); + void addFile(String name, SafeReader* data); + + DivASM(DivASMTarget target); + ~DivASM(); +}; diff --git a/src/engine/export/amigaValidation.cpp b/src/engine/export/amigaValidation.cpp index 56d3814a7..e1aa4dfdb 100644 --- a/src/engine/export/amigaValidation.cpp +++ b/src/engine/export/amigaValidation.cpp @@ -149,7 +149,7 @@ std::vector DivExportAmigaValidation::go(DivEngine* e) { } else if (waveNum<65536) { seq->writeC((i<<4)|4); seq->writeS_BE(waveNum); - } else{ + } else { seq->writeC((i<<4)|1); seq->writeC(waves[waveNum].pos>>16); seq->writeC(waves[waveNum].pos>>8); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index a4e279dad..a884c21ce 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -81,7 +81,18 @@ const char** DivPlatformAmiga::getRegisterSheet() { void DivPlatformAmiga::acquire(short** buf, size_t len) { thread_local int outL, outR, output; + for (size_t h=0; h=64) { + if ((amiga.audVol[i]&127)>=64) { output=amiga.nextOut[i]<<6; - } else if (amiga.audVol[i]<=0) { + } else if ((amiga.audVol[i]&127)==0) { output=0; } else { - output=amiga.nextOut[i]*volTable[amiga.audVol[i]][amiga.volPos]; + output=amiga.nextOut[i]*volTable[amiga.audVol[i]&63][amiga.volPos]; } if (i==0 || i==3) { outL+=(output*sep1)>>7; @@ -168,7 +182,7 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) { outL+=(output*sep2)>>7; outR+=(output*sep1)>>7; } - oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]&127))<<1; } else { oscBuf[i]->data[oscBuf[i]->needle++]=0; } @@ -190,11 +204,6 @@ void DivPlatformAmiga::irq(int ch) { if (chan[ch].irLocL==0x400 && chan[ch].irLocH==0 && chan[ch].irLen==1) { // turn off DMA rWrite(0x96,1<>1]=val; - - if (!skipRegisterWrites && dumpWrites) { - addWrite(addr,val); - } - switch (addr&0x1fe) { case 0x96: { // DMACON if (val&32768) { - if (val&1) amiga.audEn[0]=true; - if (val&2) amiga.audEn[1]=true; - if (val&4) amiga.audEn[2]=true; - if (val&8) amiga.audEn[3]=true; - if (val&512) amiga.dmaEn=true; + if (val&1) audEn[0]=true; + if (val&2) audEn[1]=true; + if (val&4) audEn[2]=true; + if (val&8) audEn[3]=true; + if (val&512) dmaEn=true; } else { if (val&1) { - amiga.audEn[0]=false; - UPDATE_DMA(0); + audEn[0]=false; } if (val&2) { - amiga.audEn[1]=false; - UPDATE_DMA(1); + audEn[1]=false; } if (val&4) { - amiga.audEn[2]=false; - UPDATE_DMA(2); + audEn[2]=false; } if (val&8) { - amiga.audEn[3]=false; - UPDATE_DMA(3); + audEn[3]=false; } if (val&512) { - amiga.dmaEn=false; + dmaEn=false; } } break; } case 0x9a: { // INTENA if (val&32768) { - if (val&128) amiga.audInt[0]=true; - if (val&256) amiga.audInt[1]=true; - if (val&512) amiga.audInt[2]=true; - if (val&1024) amiga.audInt[3]=true; + if (val&128) audInt[0]=true; + if (val&256) audInt[1]=true; + if (val&512) audInt[2]=true; + if (val&1024) audInt[3]=true; } else { - if (val&128) amiga.audInt[0]=false; - if (val&256) amiga.audInt[1]=false; - if (val&512) amiga.audInt[2]=false; - if (val&1024) amiga.audInt[3]=false; + if (val&128) audInt[0]=false; + if (val&256) audInt[1]=false; + if (val&512) audInt[2]=false; + if (val&1024) audInt[3]=false; } break; } case 0x9c: { // INTREQ if (val&32768) { if (val&128) { - amiga.audIr[0]=true; - irq(0); + audIr[0]=true; } if (val&256) { - amiga.audIr[1]=true; - irq(1); + audIr[1]=true; } if (val&512) { - amiga.audIr[2]=true; - irq(2); + audIr[2]=true; } if (val&1024) { - amiga.audIr[3]=true; - irq(3); + audIr[3]=true; } } else { - if (val&128) amiga.audIr[0]=false; - if (val&256) amiga.audIr[1]=false; - if (val&512) amiga.audIr[2]=false; - if (val&1024) amiga.audIr[3]=false; + if (val&128) audIr[0]=false; + if (val&256) audIr[1]=false; + if (val&512) audIr[2]=false; + if (val&1024) audIr[3]=false; } break; } case 0x9e: { // ADKCON if (val&32768) { - if (val&1) amiga.useV[0]=true; - if (val&2) amiga.useV[1]=true; - if (val&4) amiga.useV[2]=true; - if (val&8) amiga.useV[3]=true; - if (val&16) amiga.useP[0]=true; - if (val&32) amiga.useP[1]=true; - if (val&64) amiga.useP[2]=true; - if (val&128) amiga.useP[3]=true; + if (val&1) useV[0]=true; + if (val&2) useV[1]=true; + if (val&4) useV[2]=true; + if (val&8) useV[3]=true; + if (val&16) useP[0]=true; + if (val&32) useP[1]=true; + if (val&64) useP[2]=true; + if (val&128) useP[3]=true; } else { - if (val&1) amiga.useV[0]=false; - if (val&2) amiga.useV[1]=false; - if (val&4) amiga.useV[2]=false; - if (val&8) amiga.useV[3]=false; - if (val&16) amiga.useP[0]=false; - if (val&32) amiga.useP[1]=false; - if (val&64) amiga.useP[2]=false; - if (val&128) amiga.useP[3]=false; + if (val&1) useV[0]=false; + if (val&2) useV[1]=false; + if (val&4) useV[2]=false; + if (val&8) useV[3]=false; + if (val&16) useP[0]=false; + if (val&32) useP[1]=false; + if (val&64) useP[2]=false; + if (val&128) useP[3]=false; } break; } @@ -316,31 +310,31 @@ void DivPlatformAmiga::rWrite(unsigned short addr, unsigned short val) { bool updateDMA=false; switch (addr&15) { case 0: // LCH - amiga.audLoc[ch]&=0xffff; - amiga.audLoc[ch]|=val<<16; + audLoc[ch]&=0xffff; + audLoc[ch]|=val<<16; updateDMA=true; break; case 2: // LCL - amiga.audLoc[ch]&=0xffff0000; - amiga.audLoc[ch]|=val&0xfffe; + audLoc[ch]&=0xffff0000; + audLoc[ch]|=val&0xfffe; updateDMA=true; break; case 4: // LEN - amiga.audLen[ch]=val; + audLen[ch]=val; updateDMA=true; break; case 6: // PER - amiga.audPer[ch]=val; + audPer[ch]=val; break; case 8: // VOL - amiga.audVol[ch]=val; + audVol[ch]=val; break; case 10: // DAT - amiga.audDat[0][ch]=val&0xff; - amiga.audDat[1][ch]=val>>8; + audDat[0][ch]=val&0xff; + audDat[1][ch]=val>>8; break; } - if (updateDMA && !amiga.audEn[ch]) { + if (updateDMA && !mustDMA[ch]) { UPDATE_DMA(ch); } } @@ -349,6 +343,20 @@ void DivPlatformAmiga::rWrite(unsigned short addr, unsigned short val) { } } +void DivPlatformAmiga::rWrite(unsigned short addr, unsigned short val) { + if (addr&1) return; + + //logV("%.3x = %.4x",addr,val); + if (!skipRegisterWrites) { + writes.push(QueuedWrite(addr,val)); + regPool[addr>>1]=val; + + if (dumpWrites) { + addWrite(addr,val); + } + } +} + void DivPlatformAmiga::updateWave(int ch) { for (int i=0; i=0 && chan[i].samplesong.sampleLen) { @@ -509,9 +524,16 @@ void DivPlatformAmiga::tick(bool sysTick) { if (dmaOn) rWrite(0x96,0x8000|dmaOn); for (int i=0; i<4; i++) { - if ((dmaOn&(1< writes; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); friend class DivExportAmigaValidation; diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index f6bf5eedd..5f0d63218 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -103,6 +103,8 @@ void FurnaceGUI::doFind() { int lastRow=e->curSubSong->patLen-1; if (curQueryRangeY==1) { + finishSelection(); + firstRow=selStart.y; lastRow=selEnd.y; } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index de5fc62e1..86be7e547 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2325,6 +2325,15 @@ void FurnaceGUI::drawSettings() { } ImGui::Unindent(); + // SUBSECTION ASSETS + CONFIG_SUBSECTION("Assets"); + + bool insTypeMenuB=settings.insTypeMenu; + if (ImGui::Checkbox("Display instrument type menu when adding instrument",&insTypeMenuB)) { + settings.insTypeMenu=insTypeMenuB; + settingsChanged=true; + } + END_SECTION; } CONFIG_SECTION("Appearance") { @@ -2888,12 +2897,6 @@ void FurnaceGUI::drawSettings() { settingsChanged=true; } - bool insTypeMenuB=settings.insTypeMenu; - if (ImGui::Checkbox("Display instrument type menu when adding instrument",&insTypeMenuB)) { - settings.insTypeMenu=insTypeMenuB; - settingsChanged=true; - } - // SUBSECTION MACRO EDITOR CONFIG_SUBSECTION("Macro Editor"); ImGui::Text("Macro editor layout:");