From e03e0c7a910f8ad7ce599e5a70e1170f4ca56122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Mo=C3=9Fgraber?= Date: Sat, 21 Dec 2024 17:53:11 +0100 Subject: [PATCH] * New: Support enable state (mute) of clips. * New: Moved markers from Lanes to Arrangement to be compatible with Studio One. * Fixed: Continue conversion when end notes without start notes are found. --- README.md | 7 +++++ pom.xml | 2 +- .../format/reaper/ReaperCreator.java | 26 ++++++++++++------- .../format/reaper/ReaperDetector.java | 21 ++++++++++----- .../format/reaper/ReaperTags.java | 1 + src/main/resources/Strings.properties | 3 ++- 6 files changed, 42 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 3da8b76..6093f6d 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,13 @@ Range markers are not supported. ## Changes +### 1.2.10 + +* New: Support enable state (mute) of clips. +* New: Moved markers from Lanes to Arrangement to be compatible with Studio One. +* Fixed: Continue conversion when end notes without start notes are found. + + ### 1.2.9 * New: Support for FLAC files. diff --git a/pom.xml b/pom.xml index 9a97149..61595bc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 de.mossgrabers projectconverter - 1.2.9 + 1.2.10 ProjectConverter Convert from/to a specific DAW project format to/from generic dawproject diff --git a/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperCreator.java b/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperCreator.java index e56fac8..6e809df 100644 --- a/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperCreator.java +++ b/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperCreator.java @@ -771,18 +771,18 @@ private void convertTrack (final IMediaFiles mediaFiles, final List f * @param parentClip Some aggregated info about the parent clip(s) * @param parameters The parameters */ - private void convertItems (final Chunk trackChunk, final Track track, final Clips clips, final ParentClip parentClip, final Parameters parameters) + private void convertClips (final Chunk trackChunk, final Track track, final Clips clips, final ParentClip parentClip, final Parameters parameters) { if (clips.clips == null) return; final boolean clipsIsBeats = TimeUtils.updateIsBeats (clips, parentClip.sourceIsBeats); for (final Clip clip: clips.clips) - this.convertItem (trackChunk, track, clip, parentClip, parameters, clipsIsBeats); + this.convertClip (trackChunk, track, clip, parentClip, parameters, clipsIsBeats); } - private void convertItem (final Chunk trackChunk, final Track track, final Clip clip, final ParentClip parentClip, final Parameters parameters, final boolean clipsIsBeats) + private void convertClip (final Chunk trackChunk, final Track track, final Clip clip, final ParentClip parentClip, final Parameters parameters, final boolean clipsIsBeats) { final Double tempo = parameters.tempo; final boolean destinationIsBeats = parameters.destinationIsBeats; @@ -807,6 +807,7 @@ private void convertItem (final Chunk trackChunk, final Track track, final Clip { final ParentClip innerParentClip = new ParentClip (); innerParentClip.comment = clip.comment; + innerParentClip.mute = clip.enable != null && !clip.enable.booleanValue (); // Harmonize all time based values to the destination innerParentClip.sourceIsBeats = clipContentIsBeats; @@ -822,7 +823,7 @@ private void convertItem (final Chunk trackChunk, final Track track, final Clip innerParentClip.loopStart = clip.loopStart == null ? 0 : handleTime (clip.loopStart.doubleValue (), clipContentIsBeats, destinationIsBeats, tempo); innerParentClip.loopEnd = clip.loopEnd == null ? -1 : handleTime (clip.loopEnd.doubleValue (), clipContentIsBeats, destinationIsBeats, tempo); - this.convertItems (trackChunk, track, groupedClips, innerParentClip, parameters); + this.convertClips (trackChunk, track, groupedClips, innerParentClip, parameters); return; } @@ -855,7 +856,7 @@ private void convertItem (final Chunk trackChunk, final Track track, final Clip final Double fadeIn = handleTime (clip.fadeInTime, destinationIsBeats, parameters); final Double fadeOut = handleTime (clip.fadeOutTime, destinationIsBeats, parameters); - final Chunk itemChunk = createClipChunk (trackChunk, clip.name, start, clipDuration, offset, fadeIn, fadeOut); + final Chunk itemChunk = createClipChunk (trackChunk, clip.name, start, clipDuration, offset, fadeIn, fadeOut, parentClip.mute || (clip.enable != null && !clip.enable.booleanValue ())); if (parentClip.comment != null && !parentClip.comment.isBlank ()) createNotesChunk (itemChunk, parentClip.comment, ReaperTags.PROJECT_NOTES); @@ -910,16 +911,19 @@ private void convertLoopedAudio (final Chunk trackChunk, final Clip clip, final final Double fadeIn = handleTime (clip.fadeInTime, isBeats, parameters); final Double fadeOut = handleTime (clip.fadeOutTime, isBeats, parameters); - itemChunk = createClipChunk (trackChunk, clip.name, start, duration, clipOffset, fadeIn, fadeOut); + itemChunk = createClipChunk (trackChunk, clip.name, start, duration, clipOffset, fadeIn, fadeOut, parentClip.mute || (clip.enable != null && !clip.enable.booleanValue ())); } } - private static Chunk createClipChunk (final Chunk trackChunk, final String clipName, final double start, final double duration, final double offset, final Double fadeIn, final Double fadeOut) + private static Chunk createClipChunk (final Chunk trackChunk, final String clipName, final double start, final double duration, final double offset, final Double fadeIn, final Double fadeOut, final boolean mute) { final Chunk itemChunk = addChunk (trackChunk, ReaperTags.CHUNK_ITEM); if (clipName != null) addNode (itemChunk, ReaperTags.ITEM_NAME, clipName); + if (mute) + addNode (itemChunk, ReaperTags.ITEM_MUTE, "1"); + addNode (itemChunk, ReaperTags.ITEM_POSITION, Double.toString (start)); addNode (itemChunk, ReaperTags.ITEM_LENGTH, Double.toString (duration)); addNode (itemChunk, ReaperTags.ITEM_SAMPLE_OFFSET, Double.toString (offset)); @@ -1124,6 +1128,9 @@ private void convertArrangementLanes (final Chunk rootChunk, final Project proje if (project.arrangement == null || project.arrangement.lanes == null) return; + if (project.arrangement.markers != null) + this.convertMarkers (rootChunk, parameters, project.arrangement.markers, arrangementIsBeats); + for (final Timeline timeline: project.arrangement.lanes.lanes) if (timeline instanceof final Markers markers && markers.markers != null) this.convertMarkers (rootChunk, parameters, markers, arrangementIsBeats); @@ -1178,7 +1185,7 @@ private void convertScenes (final Chunk rootChunk, final Project project, final final double duration = TimeUtils.getDuration (clip); for (double pos = 0; pos < maxDuration; pos += duration) { - this.convertItem (trackChunk, track, clip, parentClip, parameters, isBeats); + this.convertClip (trackChunk, track, clip, parentClip, parameters, isBeats); clip.time += duration; } } @@ -1240,7 +1247,7 @@ else if (trackTimeline instanceof final Clips clips) { final ParentClip parentClip = new ParentClip (); parentClip.valuesIsBeats = timelineIsBeats; - this.convertItems (trackChunk, track, clips, parentClip, parameters); + this.convertClips (trackChunk, track, clips, parentClip, parameters); } else if (trackTimeline instanceof final Warps warps) this.convertWarps (rootOrItemChunk, parameters, warps, arrangementIsBeats); @@ -1729,6 +1736,7 @@ private static class ParentClip boolean valuesIsBeats = true; String comment; + boolean mute; // The start of the loop double loopEnd; // The end of the loop diff --git a/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperDetector.java b/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperDetector.java index 248a830..33977a6 100644 --- a/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperDetector.java +++ b/src/main/java/de/mossgrabers/projectconverter/format/reaper/ReaperDetector.java @@ -400,7 +400,7 @@ private static void convertMarkers (final DawProjectContainer dawProject, final } if (!cueMarkers.markers.isEmpty ()) - dawProject.getProject ().arrangement.lanes.lanes.add (cueMarkers); + dawProject.getProject ().arrangement.markers = cueMarkers; } @@ -639,7 +639,7 @@ private Track convertTrack (final DawProjectContainer dawProject, final Map trackTypes = this.convertItems (dawProject, mediaFilesMap, trackLanes, trackChunk, sourcePath, beatsAndTime); + final Set trackTypes = this.convertClips (dawProject, mediaFilesMap, trackLanes, trackChunk, sourcePath, beatsAndTime); if (auxReceive.isEmpty ()) { @@ -1043,7 +1043,7 @@ private Device convertDevice (final Map mediaFilesMap, final Chunk * @return The type of converted clips * @throws ParseException Could not parse the track info */ - private Set convertItems (final DawProjectContainer dawProject, final Map mediaFilesMap, final Lanes trackLanes, final Chunk trackChunk, final File sourcePath, final BeatsAndTime beatsAndTime) throws ParseException + private Set convertClips (final DawProjectContainer dawProject, final Map mediaFilesMap, final Lanes trackLanes, final Chunk trackChunk, final File sourcePath, final BeatsAndTime beatsAndTime) throws ParseException { final Set contentTypes = new HashSet<> (); @@ -1059,7 +1059,7 @@ private Set convertItems (final DawProjectContainer dawProject, fin if (node instanceof final Chunk itemChunk) { - final Clip clip = this.handleClip (dawProject, mediaFilesMap, itemChunk, sourcePath, beatsAndTime, contentTypes); + final Clip clip = this.convertClip (dawProject, mediaFilesMap, itemChunk, sourcePath, beatsAndTime, contentTypes); if (clip != null) clips.clips.add (clip); } @@ -1091,7 +1091,7 @@ private static Lanes createTrackLanes (final Project project, final Track track, * @return The clip * @throws ParseException Could not parse a clip */ - private Clip handleClip (final DawProjectContainer dawProject, final Map mediaFilesMap, final Chunk itemChunk, final File sourcePath, final BeatsAndTime beatsAndTime, final Set contentTypes) throws ParseException + private Clip convertClip (final DawProjectContainer dawProject, final Map mediaFilesMap, final Chunk itemChunk, final File sourcePath, final BeatsAndTime beatsAndTime, final Set contentTypes) throws ParseException { final Clip clip = new Clip (); @@ -1103,6 +1103,10 @@ private Clip handleClip (final DawProjectContainer dawProject, final Map 0; + if (clipMute) + clip.enable = Boolean.FALSE; + clip.name = getParam (itemChunk.getChildNode (ReaperTags.ITEM_NAME), null); clip.time = handleTime (beatsAndTime, clipPosition, false); clip.contentTimeUnit = beatsAndTime.destinationIsBeats ? TimeUnit.BEATS : TimeUnit.SECONDS; @@ -1201,7 +1205,7 @@ private Clip handleClip (final DawProjectContainer dawProject, final Map