Skip to content

Commit

Permalink
* New: Support enable state (mute) of clips.
Browse files Browse the repository at this point in the history
* New: Moved markers from Lanes to Arrangement to be compatible with Studio One.
* Fixed: Continue conversion when end notes without start notes are found.
  • Loading branch information
git-moss committed Dec 21, 2024
1 parent b6ddcf9 commit e03e0c7
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 18 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.mossgrabers</groupId>
<artifactId>projectconverter</artifactId>
<version>1.2.9</version>
<version>1.2.10</version>
<name>ProjectConverter</name>
<description>Convert from/to a specific DAW project format to/from generic
dawproject</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -771,18 +771,18 @@ private void convertTrack (final IMediaFiles mediaFiles, final List<TrackInfo> 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;
Expand All @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}


Expand Down Expand Up @@ -639,7 +639,7 @@ private Track convertTrack (final DawProjectContainer dawProject, final Map<Stri
// Convert all FX devices
channel.devices = this.convertDevices (mediaFilesMap, track, trackChunk, ReaperTags.CHUNK_FXCHAIN, folderStructure);

final Set<ContentType> trackTypes = this.convertItems (dawProject, mediaFilesMap, trackLanes, trackChunk, sourcePath, beatsAndTime);
final Set<ContentType> trackTypes = this.convertClips (dawProject, mediaFilesMap, trackLanes, trackChunk, sourcePath, beatsAndTime);

if (auxReceive.isEmpty ())
{
Expand Down Expand Up @@ -1043,7 +1043,7 @@ private Device convertDevice (final Map<String, File> mediaFilesMap, final Chunk
* @return The type of converted clips
* @throws ParseException Could not parse the track info
*/
private Set<ContentType> convertItems (final DawProjectContainer dawProject, final Map<String, File> mediaFilesMap, final Lanes trackLanes, final Chunk trackChunk, final File sourcePath, final BeatsAndTime beatsAndTime) throws ParseException
private Set<ContentType> convertClips (final DawProjectContainer dawProject, final Map<String, File> mediaFilesMap, final Lanes trackLanes, final Chunk trackChunk, final File sourcePath, final BeatsAndTime beatsAndTime) throws ParseException
{
final Set<ContentType> contentTypes = new HashSet<> ();

Expand All @@ -1059,7 +1059,7 @@ private Set<ContentType> 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);
}
Expand Down Expand Up @@ -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<String, File> mediaFilesMap, final Chunk itemChunk, final File sourcePath, final BeatsAndTime beatsAndTime, final Set<ContentType> contentTypes) throws ParseException
private Clip convertClip (final DawProjectContainer dawProject, final Map<String, File> mediaFilesMap, final Chunk itemChunk, final File sourcePath, final BeatsAndTime beatsAndTime, final Set<ContentType> contentTypes) throws ParseException
{
final Clip clip = new Clip ();

Expand All @@ -1103,6 +1103,10 @@ private Clip handleClip (final DawProjectContainer dawProject, final Map<String,
double clipPosition = getDoubleParam (itemChunk.getChildNode (ReaperTags.ITEM_POSITION), 0);
double clipDuration = getDoubleParam (itemChunk.getChildNode (ReaperTags.ITEM_LENGTH), 1);

final boolean clipMute = getDoubleParam (itemChunk.getChildNode (ReaperTags.ITEM_MUTE), 0) > 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;
Expand Down Expand Up @@ -1201,7 +1205,7 @@ private Clip handleClip (final DawProjectContainer dawProject, final Map<String,
* @return The end of the MIDI events
* @throws ParseException Could not parse the notes
*/
private static double convertMIDI (final DawProjectContainer dawProject, final Chunk sourceChunk, final Lanes lanes, final BeatsAndTime beatsAndTime) throws ParseException
private double convertMIDI (final DawProjectContainer dawProject, final Chunk sourceChunk, final Lanes lanes, final BeatsAndTime beatsAndTime) throws ParseException
{
final Notes notes = new Notes ();
lanes.lanes.add (notes);
Expand Down Expand Up @@ -1237,7 +1241,10 @@ private static double convertMIDI (final DawProjectContainer dawProject, final C
case 0x80:
final ReaperMidiEvent noteStart = findNoteStart (noteStarts, midiEvent);
if (noteStart == null)
throw new ParseException ("Malformed MIDI events in MIDI source section. End note without start note.", 0);
{
this.notifier.logError ("IDS_NOTIFY_ERR_NO_END_NOTE", Integer.toString (midiEvent.getData1 ()), Integer.toString (midiEvent.getData2 ()));
continue;
}
noteStarts.remove (noteStart);

final Note note = new Note ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class ReaperTags

protected static final String CHUNK_ITEM = "ITEM";
protected static final String ITEM_NAME = "NAME";
protected static final String ITEM_MUTE = "MUTE";
protected static final String ITEM_NOTES = "NOTES";
protected static final String ITEM_POSITION = "POSITION";
protected static final String ITEM_LENGTH = "LENGTH";
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/Strings.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
TITLE=ProjectConverter 1.2.9
TITLE=ProjectConverter 1.2.10

##################################################################################
#
Expand Down Expand Up @@ -50,6 +50,7 @@ IDS_NOTIFY_UNSUPPORTED_ENVELOPE=Automation envelope not supported for: %1\n
IDS_NOTIFY_UNKNOWN_AUDIO_FORMAT=Could not retrieve audio file format: %1\n
IDS_NOTIFY_PROCESSING=Processing
IDS_NOTIFY_FINISHED=Finished
IDS_NOTIFY_ERR_NO_END_NOTE=End note without start note: %1 %2\n

###################################################################################
# UI
Expand Down

0 comments on commit e03e0c7

Please sign in to comment.