Skip to content

Commit

Permalink
Fixes that in advanced pattern too long breaks with break track were …
Browse files Browse the repository at this point in the history
…swallowed (fixes #60).
  • Loading branch information
nwaldispuehl committed Jul 11, 2021
1 parent 6051922 commit b8b2c63
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import ch.retorte.intervalmusiccompositor.model.audiofile.AudioFileComparator;
import ch.retorte.intervalmusiccompositor.model.audiofile.IAudioFile;
import ch.retorte.intervalmusiccompositor.model.compilation.CompilationParameters;
import ch.retorte.intervalmusiccompositor.model.list.BlendMode;
import ch.retorte.intervalmusiccompositor.model.list.ListSortMode;
import ch.retorte.intervalmusiccompositor.model.list.ObservableList;
import ch.retorte.intervalmusiccompositor.model.messagebus.DebugMessage;
Expand All @@ -41,8 +42,6 @@
import static ch.retorte.intervalmusiccompositor.model.list.ListSortMode.*;
import static java.util.stream.Collectors.joining;

//import javafx.collections.ObservableList;

/**
* Main controller of the software; collects data and reacts to ui events. Implements a lot of control interfaces.
*/
Expand Down Expand Up @@ -166,8 +165,69 @@ public void startCompilation(CompilationParameters compilationParameters) {
}
}

private boolean hasUsableTracksWith(CompilationParameters compilationParameters) {
return 0 < getUsableTracks(compilationParameters.getMusicPattern());
@Override
public void markUsableTracksWith(CompilationParameters compilationParameters) {
// Music
for (IAudioFile musicFile : musicList) {
musicFile.setLongEnough(compilationParameters.getMusicPattern().stream().allMatch(p -> musicFile.isLongEnoughFor(p + effectiveBlendDuration(compilationParameters))));
}

// Break
for (IAudioFile breakFile : breakList) {
breakFile.setLongEnough(hasUsableBreakTracksWith(compilationParameters.getBreakPattern(), effectiveBlendDuration(compilationParameters)));
}
}

@Override
public boolean hasUsableTracksWith(CompilationParameters compilationParameters) {
return hasUsableMusicTracksWith(compilationParameters) && hasUsableBreakTracksWith(compilationParameters);
}

private boolean hasUsableMusicTracksWith(CompilationParameters compilationParameters) {
int usableTracks = 0;
int i = 0;
for (IAudioFile audioFile : musicList) {
if (audioFile.isOK() && audioFile.isLongEnoughFor(getIthPatternOf(compilationParameters.getMusicPattern(), i) + effectiveBlendDuration(compilationParameters))) {
usableTracks++;
}
i++;
}

return 0 < usableTracks;
}

private int getIthPatternOf(List<Integer> pattern, int i) {
if (pattern == null || pattern.isEmpty()) {
return 0;
}
return pattern.get(i % pattern.size());
}

private boolean hasUsableBreakTracksWith(CompilationParameters compilationParameters) {
return hasNoBreakTrack() || hasUsableBreakTracksWith(compilationParameters.getBreakPattern(), effectiveBlendDuration(compilationParameters));
}

private boolean hasUsableBreakTracksWith(List<Integer> pattern, int blendDuration) {
for (IAudioFile audioFile : breakList) {
if (!audioFile.isOK()) {
return false;
}

for (int p : pattern) {
if (!audioFile.isLongEnoughFor(p + blendDuration)) {
return false;
}
}
}
return true;
}

private boolean hasNoBreakTrack() {
return breakList.isEmpty();
}

private int effectiveBlendDuration(CompilationParameters compilationParameters) {
return compilationParameters.getBlendMode() == BlendMode.CROSS ? compilationParameters.getBlendDuration().intValue() : 0;
}

@Override
Expand Down Expand Up @@ -338,32 +398,9 @@ void tidyOldTemporaryFiles() {
}
}

/**
* Returns the number of tracks which are to be used for the compilation with the currently selected compilation properties.
*/
public int getUsableTracks(List<Integer> pattern) {
int usableTracks = 0;
int i = 0;
for (IAudioFile audioFile : musicList) {
if (audioFile.isOK() && audioFile.isLongEnoughFor(getIthPatternOf(pattern, i))) {
usableTracks++;
}
i++;
}

return usableTracks;
}

private int getIthPatternOf(List<Integer> pattern, int i) {
if (pattern == null || pattern.isEmpty()) {
return 0;
}
return pattern.get(i % pattern.size());
}

@Override
public int getOkTracks() {
return (int) musicList.stream().filter(IAudioFile::isOK).count();
public long getOkTracks() {
return musicList.stream().filter(IAudioFile::isOK).count();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ retorte laboratories (retorte.ch) IntervalMusicCompositor change log
IMP #59 Inactivates process button if no compilation is possible.
FIX #61 Fixes encoding tests in some environment by explicitly states encoding.
FIX #58 Fixes crash with wrong Java version by bundling Java with the application.
FIX #60 Fixes that in advanced pattern too long breaks with break track were swallowed.


2019-03-05 2.9.2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ public class AudioFile extends File implements IAudioFile {
private final Long startCutOffInMilliseconds = Long.parseLong(bundle.getString("imc.audio.cutoff.start"));
private final Long endCutOffInMilliseconds = Long.parseLong(bundle.getString("imc.audio.cutoff.end"));

private static final long serialVersionUID = 6154514892883792308L;

private Long duration = 0L;

private Float volume;
Expand Down Expand Up @@ -69,6 +67,7 @@ public class AudioFile extends File implements IAudioFile {
private final MessageProducer messageProducer;

private final Collection<ChangeListener<IAudioFile>> changeListeners = new LinkedList<>();
private boolean longEnough = true;

public AudioFile(String pathname, SoundHelper soundHelper, List<AudioFileDecoder> audioFileDecoders, BPMReaderWriter bpmReaderWriter, BPMCalculator bpmCalculator, AudioStandardizer audioStandardizer, MessageProducer messageProducer) {
super(pathname);
Expand Down Expand Up @@ -408,6 +407,16 @@ public boolean isLongEnoughFor(int extractInSeconds) {
return extractInSeconds <= ((getDuration() - startCutOffInMilliseconds - endCutOffInMilliseconds) / 1000);
}

@Override
public void setLongEnough(boolean longEnough) {
this.longEnough = longEnough;
}

@Override
public boolean isLongEnough() {
return longEnough;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof AudioFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private List<PlaylistItemFragment> createMusicPlaylist(List<IAudioFile> musicFil
IAudioFile currentAudioFile = musicFiles.get((musicTrackCounter) % musicFiles.size());
int currentSoundPattern = musicPattern.get(musicPatternCounter % musicPattern.size());

PlaylistItemFragment newMusicTrack = createPlaylistItemFrom(currentAudioFile, 1, currentSoundPattern * 1000L);
PlaylistItemFragment newMusicTrack = createPlaylistItemFrom(currentAudioFile, 1, currentSoundPattern * 1000L, false);
if (newMusicTrack != null) {
musicPlaylist.add(newMusicTrack);
musicPatternCounter++;
Expand All @@ -155,7 +155,6 @@ private List<PlaylistItemFragment> createMusicPlaylist(List<IAudioFile> musicFil
}

if (musicFiles.size() < skippedTracks) {
messageProducer.send(new ErrorMessage("Too few usable tracks."));
throw new IllegalStateException("Too few usable tracks.");
}
}
Expand All @@ -176,37 +175,30 @@ private List<PlaylistItemFragment> createBreakPlaylist(List<IAudioFile> breakFil

int desiredBreakListSize = musicPatternSize * iterations;
int breakTrackCounter = 0;
int skippedTracks = 0;

while (breakPlaylist.size() < desiredBreakListSize) {
long currentBreakPatternMs = breakPattern.get((breakTrackCounter % musicPatternSize) % breakPattern.size()) * 1000;
int currentBreakPattern = breakPattern.get((breakTrackCounter % musicPatternSize) % breakPattern.size());

if (!breakFiles.isEmpty()) {
IAudioFile currentBreakFile = breakFiles.get((breakTrackCounter % musicPatternSize) % breakFiles.size());

PlaylistItemFragment newBreakTrack = createPlaylistItemFrom(currentBreakFile, volume, currentBreakPatternMs);
PlaylistItemFragment newBreakTrack = createPlaylistItemFrom(currentBreakFile, volume, currentBreakPattern * 1000L, true);
if (newBreakTrack != null) {
breakPlaylist.add(new BreakPlaylistItemFragment(newBreakTrack));
skippedTracks = 0;
}
else {
skippedTracks++;
throw new IllegalStateException("Break track too short for desired break pattern: " + currentBreakPattern + "s.");
}

}
else {
if (isCrossFadingMode()) {
currentBreakPatternMs += (long) (blendTime * 1000);
currentBreakPattern += blendTime;
}
breakPlaylist.add(new BreakPlaylistItemFragment(createPlaylistItem(null, volume, 0L, currentBreakPatternMs)));
breakPlaylist.add(new BreakPlaylistItemFragment(createPlaylistItem(null, volume, 0L, currentBreakPattern * 1000L)));
}

breakTrackCounter++;

if (breakFiles.size() < skippedTracks) {
messageProducer.send(new ErrorMessage("Too few usable tracks."));
throw new IllegalStateException("Too few usable tracks.");
}
}

return breakPlaylist;
Expand All @@ -216,7 +208,7 @@ private boolean hasSingleZero(List<Integer> breakPattern) {
return breakPattern.size() == 1 && breakPattern.iterator().next() == 0;
}

private PlaylistItemFragment createPlaylistItemFrom(IAudioFile audioFile, double volume, long extractLengthInMilliseconds) {
private PlaylistItemFragment createPlaylistItemFrom(IAudioFile audioFile, double volume, long extractLengthInMilliseconds, boolean isBreak) {

long maximalRangeForDuration;
long trackStart = startCutOffInMilliseconds;
Expand All @@ -225,7 +217,7 @@ private PlaylistItemFragment createPlaylistItemFrom(IAudioFile audioFile, double
extractLengthInMilliseconds += (long) (blendTime * 1000);
}

if (isContinuousExtractEnumerator()) {
if (isContinuousExtractEnumerator() && !isBreak) {
if (!currentProgress.containsKey(audioFile)) {
currentProgress.put(audioFile, startCutOffInMilliseconds);
}
Expand All @@ -242,13 +234,13 @@ private PlaylistItemFragment createPlaylistItemFrom(IAudioFile audioFile, double
}

if (maximalRangeForDuration < 0) {
if (isContinuousExtractEnumerator()) {
if (isContinuousExtractEnumerator() && !isBreak) {
currentProgress.remove(audioFile);
}
return null;
}

if (isContinuousExtractEnumerator()) {
if (isContinuousExtractEnumerator() && !isBreak) {
currentProgress.put(audioFile, trackStart + extractLengthInMilliseconds);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,47 @@ public void shouldSkipTooShortTracksButNeverthelessCompletelyFillPattern() {
assertThat(tracks.get(2).getMusicFragment().getAudioFile(), is(musicTrack60s));
}

@Test
public void shouldSkipTooShortTracksButNeverthelessCompletelyFillPatternInAdvancedMode() {
// given
Playlist playlist = new Playlist(SEPARATE, 0d, SINGLE_EXTRACT, SORT, msgPrd);
playlist.setCutOff(sec(5), sec(5));

musicList.add(musicTrack60s);
musicList.add(musicTrack20s);
musicList.add(musicTrack40s);

musicPattern = pattern(10, 11);
breakPattern = pattern(1, 2);

// when
List<PlaylistItem> tracks = playlist.generatePlaylistFrom(musicList, musicPattern, breakList, breakPattern, 1, 2, soundEffectOccurrences);

// then
assertThat(tracks.size(), is(4));
assertTrackLength(tracks, 10, 1, 11, 2, 10, 1, 11, 2);
assertTotalLength(playlist, tracks, 48);
assertThat(tracks.get(0).getMusicFragment().getAudioFile(), is(musicTrack60s));
assertThat(tracks.get(1).getMusicFragment().getAudioFile(), is(musicTrack40s));
assertThat(tracks.get(2).getMusicFragment().getAudioFile(), is(musicTrack60s));
assertThat(tracks.get(3).getMusicFragment().getAudioFile(), is(musicTrack40s));
}

@Test(expected = IllegalStateException.class)
public void shouldNotAllowNotSufficientBreakTrack() {
// given
Playlist playlist = new Playlist(SEPARATE, 0d, SINGLE_EXTRACT, SORT, msgPrd);
playlist.setCutOff(sec(5), sec(5));

musicList.add(musicTrack20s);
breakList.add(breakTrack20s);

musicPattern = pattern(8, 8, 8);
breakPattern = pattern(8, 12, 8);

// when this, then throw exception
playlist.generatePlaylistFrom(musicList, musicPattern, breakList, breakPattern, 1, 1, soundEffectOccurrences);
}

@Test
public void shouldTakeTheSameTrackInContinuousMode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,18 @@ public interface IAudioFile extends Comparable<File> {
*/
boolean isLongEnoughFor(int extractInSeconds);

/**
* Sets the long enough marker to either true ('long enough'), or false ('too short').
*
* @param longEnough true if the track is long enough.
*/
void setLongEnough(boolean longEnough);

/**
* Whether this file was marked long enough.
*
* @return true if this file is considered long enough for the compilation.
*/
boolean isLongEnough();

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.List;

import ch.retorte.intervalmusiccompositor.model.audiofile.IAudioFile;
import ch.retorte.intervalmusiccompositor.model.compilation.CompilationParameters;
import ch.retorte.intervalmusiccompositor.model.list.BlendMode;
import ch.retorte.intervalmusiccompositor.model.list.ListSortMode;
import ch.retorte.intervalmusiccompositor.model.list.ObservableList;
import ch.retorte.intervalmusiccompositor.model.soundeffect.SoundEffect;
Expand Down Expand Up @@ -51,9 +53,11 @@ public interface MusicListControl {

void setBreakBpm(int index, int bpm);

int getUsableTracks(List<Integer> pattern);
void markUsableTracksWith(CompilationParameters compilationParameters);

int getOkTracks();
boolean hasUsableTracksWith(CompilationParameters compilationParameters);

long getOkTracks();

void moveTrack(int sourceIndex, int destinationIndex);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,22 +197,27 @@ private void setStatusWith(IAudioFile audioFile) {
case IN_PROGRESS:
imageView.setImage(processing);
status.setText(resourceBundle.getString("ui.form.music_list.loading_text"));
return;
break;
case ERROR:
imageView.setImage(error);
status.setText(audioFile.getErrorMessage());
return;
break;
case OK:
imageView.setImage(ok);
status.setText(audioFile.getSource().getParentFile().getAbsolutePath());
return;
break;
case QUEUED:
imageView.setImage(queued);
status.setText(resourceBundle.getString("ui.form.music_list.queuing_text"));
return;
break;
default:
imageView.setImage(warning);
}

if (!audioFile.isLongEnough()) {
imageView.setImage(warning);
status.setText(resourceBundle.getString("ui.form.music_list.tooshort_error"));
}
}

private void setContextMenuWith(IAudioFile audioFile) {
Expand Down
Loading

0 comments on commit b8b2c63

Please sign in to comment.