Skip to content

Commit 28fd497

Browse files
committed
V3.9.1 Update
1 parent e6c7713 commit 28fd497

13 files changed

+423
-314
lines changed

README.md

+111-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# JavaMod V3.8
1+
# JavaMod V3.9.1
22
JavaMod - a java based multimedia player for Protracker, Fast Tracker,
33
Impulse Tracker, Scream Tracker and other mod files plus
44
SID, MP3, WAV, OGG, APE, FLAC, MIDI, AdLib ROL-Files (OPL), ...
@@ -17,6 +17,13 @@ To start the command line version enter:
1717
On Linux consider starting with OpenGL render pipeline activated:
1818
java -Dsun.java2d.opengl=true -jar ./javamod.jar
1919

20+
## Remarks to 3.9.x version updates
21+
With JavaMod versions 4.0 to 5.0 I want to integrate Midi and AdLib support.
22+
However, before starting that I want to have all test mods of Schism and
23+
Open ModPlug Tracker to work. We finished MOD and most of XM with this version
24+
and a whole lot of other stuff as well. So I decided to release new version
25+
with minor version number updates to have you participate in these changes!
26+
2027
## Download of compiled version and source code
2128
* https://javamod.de/javamod.php
2229
* https://quippy.de/mod.php
@@ -53,17 +60,113 @@ JavaMod incorporates modified versions of the following libraries:
5360
## Known issues:
5461
* With PulseAudio:
5562
* gapless audio streams do not work if SourceLine Buffers drain out
56-
* scrambled sound
63+
* scrambled sound (especially with PipeWire)
5764
* With KDE:
5865
* JDialogs, when set visible, will not come to front
59-
* X-Mas Decoration does not work as intended
6066
* Tray Icon: mouse wheel (volume control) & keyboard shortcuts do not work
6167

6268
## Planned:
63-
* WavPack and MusePack support
64-
* MO3 support
65-
* Midi and AdLib/OPL with Mods
66-
* read 7z archives
69+
* finish loading of OMPT extended instrument / song data / mixer data
70+
* optimize recognition of different trackers - for whatever that is worth it
71+
* reading at least Midi Config with XMs / ITs
72+
* VSTiVolume, SamplePreAmp, MixLevels - look, what OMPT has to say
73+
* check for further missing MPTM Effects like Reverb and Surround commands
74+
* Quad Speaker mixing (rear speakers)
75+
+ LongList:
76+
* Midi and AdLib/OPL with Mods
77+
* WavPack and MusePack support
78+
* MO3 support
79+
* read from 7z archives
80+
81+
## New in Version 3.9.1
82+
* NEW: Colorful pattern display with previous and next pattern displayed in dim
83+
colors. Following pattern optimized, drawn completely manually and with
84+
full clipping of unseen parts to gain speed.
85+
Effects are displayed in different colors per category, like MPT does it
86+
During playback, you can select a pattern for seeking into the piece
87+
* NEW: Moved the UpdateThread of ModPatternDialog into a separate class and
88+
moved wiring into ModContainer
89+
* NEW: added also an editor bar to the pattern display to move with cursor keys
90+
and page up/down, home/end, ... plus modifier keys.
91+
Press ESC to leave editor mode. (The editor mode is not a real editor!)
92+
* NEW: A double click on the instrument column will open instrument/sample
93+
dialog for display
94+
* NEw: Zoom for instrument and sample display
95+
* NEW: Overhaul of most of the graphical implementations
96+
* NEW: removed test classes from project
97+
* NEW: Added a headless mode for command line usage. That way no GUI elements
98+
are created.
99+
(Explanation: So far we used the ConfigPanels to store the current config
100+
of a mixer. Now this is done locally and only transported to/from the
101+
GUIs, if they are present)
102+
* NEW: Added ModPlug Tracker MPTM-Files for loading. However, not all MPTM-
103+
effects are yet supported (there are not that many missing though)
104+
See next list:
105+
* NEW: added support for OMPT special "Extension Effect" feature
106+
* NEW: added OMPT extended song properties (not all yet!)
107+
* NEW: added OMPT extended instrument properties (by far not all yet!)
108+
* NEW: added OMPT cue points
109+
* NEW: added OMPT tempo modes CLASSIC, ALTERNATIVE and MODERN plus TempSwing
110+
* NEW: added OMPT pattern names / channel names / channel coloring
111+
* NEW: added OMPT 127 Channel support
112+
* NEW: added OMPT Kaiser interpolation and WindowedFIR with low pass filter
113+
* NEW: (BETA, UNTESTED) added support for XM version <0x0104, but could not test
114+
as I am missing old FT2 XMs for that
115+
* NEW: more sanity checks in XM loading. Had found some very corrupted ones
116+
* NEW: Added ADPCM decoding for MODs, XMs, S3M and ITs - however, I am very sure
117+
that nobody is using this encoder anymore
118+
* NEW: added a simulation of the E00/E01 filter effect with MODs and XMs (we re-
119+
use the resonance low pass filter of ITs here...). If I ever implement
120+
an A500/A1200 Paula filter we would use that one to get a more realistic
121+
emulation
122+
* NEW: added FunkIt! (EFx effect) for mod files. Is that really used?!
123+
* NEW: added an info dialog for SID tunes (and fixed NULL-Pointer exception with
124+
non existent info panels as well - there are none now however...)
125+
* NEW: added support for ITs in sample mode only (flags bit 2 not set)
126+
* FIX: setting FineTune via effect now works also in MOD/XM
127+
* FIX: XM: reading periods from tables instead of on the fly calculations
128+
* FIX: Enhanced ProTracker 1/2 compatibility by fixing everything to make these
129+
test MODs work: https://wiki.openmpt.org/Development:_Test_Cases/MOD
130+
(many, many changes...! Let's just say tempo and sample setting is very
131+
different now - and many other things)
132+
* FIX: Enhanced FastTracker 2 compatibility by fixing everything to make these
133+
test MODs work: https://wiki.openmpt.org/Development:_Test_Cases/XM
134+
(many, many changes...!)
135+
* FIX: Vibrato, Panbrello, Tremolo fixed for MOD, XM, S3M and IT
136+
* FIX: Overhaul of automatic volume ramping for new instruments. Is now only
137+
done when a new tick starts (only on new row did not do the trick!) and
138+
considers now the target mixing buffer size.
139+
I don't do that like 8bitbubsy: add a new channel with a volume ramp
140+
down for the "leaving" sample and do a ramp up with the new one. Did not
141+
work for me with synthesis.mod from Rymix - still clicks...
142+
* FIX: As now volume ramping does work and we also have the smooth OMPT ramping
143+
over one whole tick, we *must* deactivate that, if a volume is set
144+
* FIX: no silence at beginning of play back anymore - starts instantly now
145+
* FIX: added tempo memory for IT tempo slides
146+
* FIX: S3M ignores illegal pattern break commands
147+
* FIX: (Smooth) Midi Macros for XMs fixed
148+
* FIX: Smooth midi macros initial value (lastZxxParam) must be 0x7F not 0
149+
* FIX: Effects Parameter Extension and smooth midi macros are swapped between
150+
XMs and ITs
151+
* FIX: PatternFrameDelays add up. After PatternDelay, PatternFrameDelays must be
152+
restored for ITs / S3M. With XMs we also need to process tick effects,
153+
not row effects. But fine effects (played on tick zero) must be played as
154+
well. Fixed for all XMs, ITs, S3M, MPT
155+
* FIX: NoteDelay need to do row effects with EFG memory
156+
* FIX: Registering the Mixers at the ModPatternDialog resulted in an exception
157+
when JavaMod was started on the command line. Also fixed with Headless
158+
* FIX: Renamed "Wide Stereo Mix" to "Surround Mix", as that is what is really
159+
done
160+
* FIX: Loading and displaying of a play list is now much faster
161+
* FIX: CommandLine did not read parameter "buffer size" correctly
162+
* FIX: remove effect names when play back stopped
163+
* FIX: muting a channel will not stop its rendering anymore
164+
* FIX: Playback in Pattern- and SampleDialog must respect finetune settings
165+
* FIX: APE files in 8Bit were set to signed samples - which is wrong
166+
* FIX: MP3 ICY Streams with no song name meta tag yet send will identify as
167+
"Streaming" and not pick a default name from the URL
168+
* FIX: On MacOS "mode.getRefreshRate" will return "REFRESHRATE_UNKNOWN" - which
169+
is 0. Thanks to MasterFlomaster1 for finding this.
67170

68171
## New in Version 3.8
69172
* NEW: Implemented an automatic update check every 30 days. *Disable* it in the
@@ -303,7 +406,7 @@ JavaMod incorporates modified versions of the following libraries:
303406
* FIX: Log.debug (instead of Log.info) for missing effects
304407
* FIX: When a MOD was playing, changing MOD sample rate, channels, bits also
305408
changed current audio line, even though e.g. mp3 is playing. Not healthy
306-
for playback if the global line is cut away during playing
409+
for play back if the global line is cut away during playing
307410
(BTW: same for SIDs)
308411
* FIX: Instrument set, but no note - with XMs/ITs lookup in mapping resulted in
309412
Exception

source/de/quippy/javamod/multimedia/mod/ModConstants.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,8 @@ public static enum PanBits { Pan4Bit, Pan6Bit, Pan8Bit }
940940
// Table for Invert Loop and Funk Repeat effects (EFx, .MOD only)
941941
public static final int modEFxTable[] =
942942
{
943-
0, 5, 6, 7, 8, 10, 11, 13, 16, 19, 22, 26, 32, 43, 64, 128
943+
0x00, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D,
944+
0x10, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80
944945
};
945946

946947
/**

source/de/quippy/javamod/multimedia/mod/gui/EnvelopeImagePanel.java

+28-29
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,15 @@ public EnvelopeImagePanel()
6060
setDoubleBuffered(true);
6161
}
6262

63-
private void drawGrid(Graphics g, int top, int left, int width, int height)
63+
private int getX(final int xPos)
64+
{
65+
return (xPos * getWidth()) / MAX_WIDTH;
66+
}
67+
private int getY(final int yPos)
68+
{
69+
return getHeight() - ((yPos * getHeight()) >> 6);
70+
}
71+
private void drawGrid(final Graphics g, final int top, final int left, final int width, final int height)
6472
{
6573
final int halfHeight = height>>1;
6674

@@ -69,7 +77,7 @@ private void drawGrid(Graphics g, int top, int left, int width, int height)
6977

7078
for (int i=0; i<MAX_WIDTH; i++)
7179
{
72-
int x = (i * width) / MAX_WIDTH;
80+
int x = getX(i);
7381
if ((i % (SMALLESTGRID*4*4))==0)
7482
{
7583
g.setColor(GRID_COLOR);
@@ -89,19 +97,21 @@ private void drawGrid(Graphics g, int top, int left, int width, int height)
8997
}
9098
}
9199
}
92-
private int getX(final int xPos)
100+
private void drawLoopLine(final Graphics g, final int startPoint, final int endPoint, final int width, final int height, final Color col)
93101
{
94-
return (xPos * getWidth()) / MAX_WIDTH;
95-
}
96-
private int getY(final int yPos)
97-
{
98-
return getHeight() - ((yPos * getHeight()) >> 6);
102+
g.setColor(col);
103+
int x = getX(envelope.positions[startPoint]) - BOXWIDTH;
104+
if (x<0) x=0; else if (x>width) x=width;
105+
g.drawLine(x, 0, x, height);
106+
x = getX(envelope.positions[endPoint]) + BOXWIDTH + 1;
107+
if (x<0) x=0; else if (x>width) x=width;
108+
g.drawLine(x, 0, x, height);
99109
}
100110
/**
101111
* @since 07.01.2024
102112
* @param gfx
103113
*/
104-
private void drawEnvelope(Graphics g)
114+
private void drawEnvelope(final Graphics g)
105115
{
106116
final int width = getWidth();
107117
final int height = getHeight();
@@ -131,26 +141,8 @@ private void drawEnvelope(Graphics g)
131141
oldx = x;
132142
oldy = y;
133143
}
134-
if (envelope.loop)
135-
{
136-
g.setColor(LOOP_COLOR);
137-
int x = getX(envelope.positions[envelope.loopStartPoint]) - BOXWIDTH;
138-
if (x<0) x=0; else if (x>width) x=width;
139-
g.drawLine(x, 0, x, height);
140-
x = getX(envelope.positions[envelope.loopEndPoint]) + BOXWIDTH + 1;
141-
if (x<0) x=0; else if (x>width) x=width;
142-
g.drawLine(x, 0, x, height);
143-
}
144-
if (envelope.sustain)
145-
{
146-
g.setColor(SUSTAINLOOP_COLOR);
147-
int x = getX(envelope.positions[envelope.sustainStartPoint]) - BOXWIDTH;
148-
if (x<0) x=0; else if (x>width) x=width;
149-
g.drawLine(x, 0, x, height);
150-
x = getY(envelope.positions[envelope.sustainEndPoint]) + BOXWIDTH + 1;
151-
if (x<0) x=0; else if (x>width) x=width;
152-
g.drawLine(x, 0, x, height);
153-
}
144+
if (envelope.loop) drawLoopLine(g, envelope.loopStartPoint, envelope.loopEndPoint, width, height, LOOP_COLOR);
145+
if (envelope.sustain) drawLoopLine(g, envelope.sustainStartPoint, envelope.sustainEndPoint, width, height, SUSTAINLOOP_COLOR);
154146
}
155147
}
156148
/**
@@ -176,4 +168,11 @@ public void setEnvelope(Envelope envelope)
176168
this.envelope = envelope;
177169
repaint();
178170
}
171+
/**
172+
* @return the envelope
173+
*/
174+
public Envelope getEnvelope()
175+
{
176+
return envelope;
177+
}
179178
}

source/de/quippy/javamod/multimedia/mod/gui/EnvelopePanel.java

+75-1
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,17 @@
2121
*/
2222
package de.quippy.javamod.multimedia.mod.gui;
2323

24+
import java.awt.Dimension;
25+
import java.awt.EventQueue;
2426
import java.awt.GridBagLayout;
27+
import java.awt.Insets;
2528
import java.awt.LayoutManager;
29+
import java.awt.event.ItemEvent;
30+
import java.awt.event.ItemListener;
2631

32+
import javax.swing.JComboBox;
2733
import javax.swing.JPanel;
34+
import javax.swing.JScrollPane;
2835

2936
import de.quippy.javamod.main.gui.components.FixedStateCheckBox;
3037
import de.quippy.javamod.multimedia.mod.loader.instrument.Envelope;
@@ -38,6 +45,7 @@
3845
public class EnvelopePanel extends JPanel
3946
{
4047
private static final long serialVersionUID = 5511415780545189305L;
48+
private static String [] ZOOM_TYPES = new String [] { "Auto", "2:1", "4:1", "8:1", "16:1", "32:1" };
4149

4250
private EnvelopeImagePanel envelopeImagePanel = null;
4351

@@ -46,6 +54,8 @@ public class EnvelopePanel extends JPanel
4654
private FixedStateCheckBox isFilterEnabled = null;
4755
private FixedStateCheckBox isLoopEnabled = null;
4856
private FixedStateCheckBox isSustainEnabled = null;
57+
private JComboBox<String> zoomSelector = null;
58+
private JScrollPane imageBufferScrollPane = null;
4959

5060
/**
5161
* Constructor for EnvelopePanel
@@ -91,7 +101,8 @@ private void initialize()
91101
add(getIsFilterEnabled(), Helpers.getGridBagConstraint(2, 0, 1, 1, java.awt.GridBagConstraints.NONE, java.awt.GridBagConstraints.WEST, 0.0, 0.0));
92102
add(getIsLoopEnabled(), Helpers.getGridBagConstraint(3, 0, 1, 1, java.awt.GridBagConstraints.NONE, java.awt.GridBagConstraints.WEST, 0.0, 0.0));
93103
add(getIsSustainEnabled(), Helpers.getGridBagConstraint(4, 0, 1, 1, java.awt.GridBagConstraints.NONE, java.awt.GridBagConstraints.WEST, 0.0, 0.0));
94-
add(getEnvelopeImagePanel(), Helpers.getGridBagConstraint(0, 1, 1, 0, java.awt.GridBagConstraints.BOTH, java.awt.GridBagConstraints.WEST, 1.0, 1.0));
104+
add(getZoomSelector(), Helpers.getGridBagConstraint(5, 0, 1, 1, java.awt.GridBagConstraints.NONE, java.awt.GridBagConstraints.WEST, 0.0, 0.0));
105+
add(getImageBufferScrollPane(), Helpers.getGridBagConstraint(0, 1, 1, 0, java.awt.GridBagConstraints.BOTH, java.awt.GridBagConstraints.WEST, 1.0, 1.0));
95106
}
96107
private FixedStateCheckBox getIsEnabled()
97108
{
@@ -148,6 +159,40 @@ private FixedStateCheckBox getIsSustainEnabled()
148159
}
149160
return isSustainEnabled;
150161
}
162+
private JComboBox getZoomSelector()
163+
{
164+
if (zoomSelector==null)
165+
{
166+
zoomSelector = new JComboBox<String>();
167+
zoomSelector.setName("zoomSelector");
168+
zoomSelector.setFont(Helpers.getDialogFont());
169+
170+
for (int i=0; i<ZOOM_TYPES.length; i++) zoomSelector.addItem(ZOOM_TYPES[i]);
171+
zoomSelector.addItemListener(new ItemListener()
172+
{
173+
@Override
174+
public void itemStateChanged(ItemEvent e)
175+
{
176+
final Envelope theEnvelope = getEnvelopeImagePanel().getEnvelope();
177+
if (theEnvelope==null) return;
178+
changeZoom(getZoomSelector().getSelectedIndex());
179+
}
180+
});
181+
}
182+
183+
return zoomSelector;
184+
}
185+
private JScrollPane getImageBufferScrollPane()
186+
{
187+
if (imageBufferScrollPane==null)
188+
{
189+
imageBufferScrollPane = new javax.swing.JScrollPane();
190+
imageBufferScrollPane.setName("imageBufferScrollPane");
191+
imageBufferScrollPane.setViewportView(getEnvelopeImagePanel());
192+
imageBufferScrollPane.setDoubleBuffered(true);
193+
}
194+
return imageBufferScrollPane;
195+
}
151196
private EnvelopeImagePanel getEnvelopeImagePanel()
152197
{
153198
if (envelopeImagePanel==null)
@@ -156,6 +201,35 @@ private EnvelopeImagePanel getEnvelopeImagePanel()
156201
}
157202
return envelopeImagePanel;
158203
}
204+
private void changeZoom(final int newZoom)
205+
{
206+
final Dimension d = getEnvelopeImagePanel().getSize();
207+
final Envelope theEnvelope = getEnvelopeImagePanel().getEnvelope();
208+
if (theEnvelope!=null)
209+
{
210+
final int scrollBarHeight = getImageBufferScrollPane().getHorizontalScrollBar().getPreferredSize().height;
211+
final Insets inset = getImageBufferScrollPane().getInsets();
212+
d.height= getImageBufferScrollPane().getHeight() - inset.top - inset.bottom - (scrollBarHeight<<1);
213+
d.width = (getImageBufferScrollPane().getWidth() - inset.left - inset.right) << newZoom;
214+
}
215+
EventQueue.invokeLater(new Runnable()
216+
{
217+
public void run()
218+
{
219+
try
220+
{
221+
getEnvelopeImagePanel().setSize(d);
222+
getEnvelopeImagePanel().setMinimumSize(d);
223+
getEnvelopeImagePanel().setMaximumSize(d);
224+
getEnvelopeImagePanel().setPreferredSize(d);
225+
}
226+
catch (Throwable ex)
227+
{
228+
// Keep it!
229+
}
230+
}
231+
});
232+
}
159233
public void setEnvelope(final Envelope envelope)
160234
{
161235
if (envelope!=null)

source/de/quippy/javamod/multimedia/mod/loader/Module.java

-3
Original file line numberDiff line numberDiff line change
@@ -1455,15 +1455,12 @@ protected boolean loadExtendedSongProperties(final ModfileInputStream inputStrea
14551455
break;
14561456
case 0x5350412E: //"SPA." - SamplePreAmp
14571457
mixingPreAmp = (int)inputStream.readIntelBytes(size);
1458-
if (mixingPreAmp > ModConstants.MAX_MIXING_PREAMP) mixingPreAmp = ModConstants.MAX_MIXING_PREAMP;
14591458
break;
14601459
case 0x56535456: //"VSTV" - VSTiVolume
14611460
synthMixingPreAmp = (int)inputStream.readIntelBytes(size);
1462-
if (synthMixingPreAmp > ModConstants.MAX_MIXING_PREAMP) synthMixingPreAmp = ModConstants.MAX_MIXING_PREAMP;
14631461
break;
14641462
case 0x4447562E: //"DGV." - defaultGlobalVolume
14651463
baseVolume = (int)inputStream.readIntelBytes(size);
1466-
if (baseVolume > ModConstants.MAXGLOBALVOLUME) baseVolume = ModConstants.MAXGLOBALVOLUME;
14671464
break;
14681465
case 0x52502E2E: //"RP.." - Song Restart
14691466
final int restartPosition = (int)inputStream.readIntelBytes(size);

0 commit comments

Comments
 (0)