public ReceiveDiff(Song.Receive a, Song.Receive b, int index) { this.a = a; this.b = b; this.index = index; sendingTrackIndex = a.SendingTrackIndex != b.SendingTrackIndex; receivingChannelIndex = a.ReceivingChannelIndex != b.ReceivingChannelIndex; volume = a.Volume != b.Volume; }
public Song Process(Project project, ILog logger) { this.logger = logger; this.project = project; var song = new Song(); song.Tempo = (int)project.Tempo; song.SampleRate = 44100; sampleRate = song.SampleRate; tempo = song.Tempo; song.Length = GetSongLength(); // remove unwanted insert channels for (var i = 1; i < project.Inserts.Length; i++) { var insert = project.Inserts[i]; if (!IsInsertUsed(insert)) { project.Inserts[i] = null; } } // deal with sends and routing // master track is insert channel 0 var master = project.Inserts[0]; // add both insert and channel tracks trackReceives = new Dictionary <object, List <FLReceive> >(); foreach (var projectTrack in project.Inserts) { if (projectTrack != null) { trackReceives.Add(projectTrack, new List <FLReceive>()); } } foreach (var channel in project.Channels) { if (channel.Data is GeneratorData) { trackReceives.Add(channel, new List <FLReceive>()); } } // link insert track routes foreach (var projectTrack in this.project.Inserts) { if (projectTrack == null) { continue; } for (int i = 0; i < projectTrack.Routes.Length; i++) { if (projectTrack.Routes[i]) { // route enabled var sendTrack = project.Inserts[i]; var channelIndex = projectTrack.RouteVolumes[i] == 0 ? 2 : 0; // very odd but sidechains are volume 0 which means 1 volume double volume = 1; if (projectTrack.RouteVolumes[i] > 0) { volume = (double)projectTrack.RouteVolumes[i] / 12800; } trackReceives[sendTrack].Add(new FLReceive(projectTrack, channelIndex, volume)); } } } // link channel track routes foreach (var channel in project.Channels) { if (channel.Data is GeneratorData) { var genData = (GeneratorData)channel.Data; var insert = project.Inserts[genData.Insert]; trackReceives[insert].Add(new FLReceive(channel, 0, genData.Volume / 10000)); // no idea why FL decided on two different volume types! } } visitedTracks = new List <object>(); orderedTracks = new List <object>(); // visit master to order tracks using DFS VisitTrack(master); var projectTracksToSongTracks = new Dictionary <object, Song.Track>(); foreach (var projectTrack in orderedTracks) { var track = ConvertTrack(projectTrack); projectTracksToSongTracks.Add(projectTrack, track); song.Tracks.Add(track); } // convert each tracks data foreach (var kvp in projectTracksToSongTracks) { foreach (var projectReceive in trackReceives[kvp.Key]) { if (projectTracksToSongTracks.ContainsKey(projectReceive.SendingTrack)) { var receive = new Song.Receive(); receive.SendingTrackIndex = song.Tracks.IndexOf(projectTracksToSongTracks[projectReceive.SendingTrack]); receive.ReceivingChannelIndex = projectReceive.ReceivingChannelIndex; receive.Volume = (float)projectReceive.Volume; kvp.Value.Receives.Add(receive); } } } return(song); }
public Song.Track CreateTrack(ReaperTrack reaperTrack) { var track = new Song.Track(); track.Name = reaperTrack.TrackName; track.Volume = reaperTrack.VolumePanning.Volume; if (reaperTrack.VolumePanning.Pan != 0) { logger.WriteLine("WARNING: Pan value {0} on track {1} unsupported", reaperTrack.VolumePanning.Pan, reaperTrack.TrackName); } // add receives foreach (var r in reaperTrack.Receives) { if (r.ReceiveFader != ReaperFader.PostFader) { logger.WriteLine("WARNING: Receive fader type of {0} on track {1} unsupported", r.ReceiveFader, reaperTrack.TrackName); } var receive = new Song.Receive(); receive.SendingTrackIndex = r.ReceiveTrackId + 1; // master always zero, so tracks are out by one receive.ReceivingChannelIndex = r.DestinationChannelIndex; receive.Volume = r.Volume; track.Receives.Add(receive); } foreach (var f in reaperTrack.EffectsChain) { if (f.Wet != 0) { logger.WriteLine("WARNING: Wet value for effect {0} on track {1} unsupported", f.Vst.VstFile, reaperTrack.TrackName); } Song.Device device = null; Song.DeviceId deviceId; if (Enum.TryParse <Song.DeviceId>(f.Vst.VstFile.Replace(".dll", "").Replace(".64", ""), out deviceId)) { device = new Song.Device(); device.Id = deviceId; device.Chunk = f.Vst.VstChunkData; } if (device == null) { logger.WriteLine("WARNING: Device skipped (unsupported plugin): " + f.Vst.VstFile); } /*else if (f.Vst.Bypass) // TODO: Parse out Bypass * { * logger.WriteLine("WARNING: Device skipped (bypass enabled): " + projectDevice.PluginDll); * }*/ track.Devices.Add(device); var deviceIndex = track.Devices.IndexOf(device); foreach (var a in f.Automations) { track.Automations.Add(ConvertAutomation(a, deviceIndex, reaperTrack.TrackName)); } track.Events = ConvertMidi(reaperTrack.MediaItems); } return(track); }
public Song Process(LiveProject project, ILog logger) { this.logger = logger; var song = new Song(); song.Tempo = (int)project.Tempo; song.SampleRate = 44100; var projectLoopEnd = project.LoopStart + project.LoopLength; trackReceives = new Dictionary <LiveProject.Track, List <Receive> >(); foreach (var projectTrack in project.Tracks) { trackReceives.Add(projectTrack, new List <Receive>()); } foreach (var projectTrack in project.Tracks) { foreach (var send in projectTrack.Sends) { if (send.IsActive) { trackReceives[send.ReceivingTrack].Add(new Receive(projectTrack, send.ReceivingChannelIndex - 1, send.Volume)); } } } project.MasterTrack.Name = project.MasterTrack.Name == "" ? "Master" : project.MasterTrack.Name; visitedTracks = new List <LiveProject.Track>(); orderedTracks = new List <LiveProject.Track>(); visitTrack(project.MasterTrack); var projectTracksToSongTracks = new Dictionary <LiveProject.Track, Song.Track>(); var songTrackEvents = new Dictionary <Song.Track, List <Event> >(); double?minEventTime = null; double?maxEventTime = null; foreach (var projectTrack in orderedTracks) { var track = new Song.Track(); track.Name = projectTrack.Name; track.Volume = (float)projectTrack.Volume; foreach (var projectDevice in projectTrack.Devices) { Song.Device device = null; Song.DeviceId deviceId; if (Enum.TryParse <Song.DeviceId>(projectDevice.PluginDll.Replace(".dll", "").Replace(".64", ""), out deviceId)) { device = new Song.Device(); device.Id = deviceId; device.Chunk = projectDevice.RawData != null ? (byte[])projectDevice.RawData.Clone() : new byte[0]; } if (device == null) { logger.WriteLine("WARNING: Device skipped (unsupported plugin): " + projectDevice.PluginDll); } else if (projectDevice.Bypass) { logger.WriteLine("WARNING: Device skipped (bypass enabled): " + projectDevice.PluginDll); } else { track.Devices.Add(device); foreach (var floatParameter in projectDevice.FloatParameters) { if (floatParameter.Id >= 0) { var automation = new Song.Automation(); automation.DeviceIndex = track.Devices.IndexOf(device); automation.ParamId = floatParameter.Id; foreach (var e in floatParameter.Events) { if (e.Time >= 0.0) { var point = new Song.Point(); point.TimeStamp = secondsToSamples(e.Time, (double)song.Tempo, (double)song.SampleRate); point.Value = e.Value; automation.Points.Add(point); } } if (automation.Points.Count > 0) { track.Automations.Add(automation); } } } } } var events = new List <Event>(); foreach (var midiClip in projectTrack.MidiClips) { if (!midiClip.IsDisabled) { var loopLength = midiClip.LoopEnd - midiClip.LoopStart; for (var currentTime = midiClip.CurrentStart; currentTime < midiClip.CurrentEnd; currentTime += loopLength) { foreach (var keyTrack in midiClip.KeyTracks) { foreach (var note in keyTrack.Notes) { if (note.IsEnabled) { var startTime = note.Time - (currentTime - midiClip.CurrentStart) - midiClip.LoopStartRelative; while (startTime < 0.0) { startTime += loopLength; } startTime = currentTime + startTime - midiClip.LoopStart; var endTime = startTime + note.Duration; if ((startTime >= midiClip.CurrentStart && startTime < midiClip.CurrentEnd) && (!project.IsLoopOn || ( startTime >= project.LoopStart && startTime < projectLoopEnd))) { endTime = Math.Min(endTime, midiClip.CurrentEnd); if (project.IsLoopOn) { endTime = Math.Min(endTime, projectLoopEnd); } if (endTime > startTime) { var startEvent = new Event(); startEvent.Time = startTime; startEvent.Type = Song.EventType.NoteOn; startEvent.Note = (byte)keyTrack.MidiKey; startEvent.Velocity = (byte)note.Velocity; events.Add(startEvent); var endEvent = new Event(); endEvent.Time = endTime; endEvent.Type = Song.EventType.NoteOff; endEvent.Note = (byte)keyTrack.MidiKey; events.Add(endEvent); } } } } } } } } events.Sort((a, b) => { if (a.Time > b.Time) { return(1); } if (a.Time < b.Time) { return(-1); } if (a.Type == Song.EventType.NoteOn && b.Type == Song.EventType.NoteOff) { return(1); } if (a.Type == Song.EventType.NoteOff && b.Type == Song.EventType.NoteOn) { return(-1); } return(0); }); foreach (var e in events) { if (!minEventTime.HasValue || e.Time < minEventTime.Value) { minEventTime = e.Time; } if (!maxEventTime.HasValue || e.Time > maxEventTime.Value) { maxEventTime = e.Time; } } projectTracksToSongTracks.Add(projectTrack, track); songTrackEvents.Add(track, events); song.Tracks.Add(track); } double songStartTime, songEndTime; if (project.IsLoopOn) { songStartTime = project.LoopStart; songEndTime = projectLoopEnd; } else if (minEventTime.HasValue && maxEventTime.HasValue) { songStartTime = minEventTime.Value; songEndTime = maxEventTime.Value; } else { throw new Exception("Couldn't find song start/end times"); } song.Length = (songEndTime - songStartTime) * 60.0 / (double)song.Tempo; foreach (var kvp in songTrackEvents) { var track = kvp.Key; var events = kvp.Value; int lastTimeStamp = 0; foreach (var e in events) { var songEvent = new Song.Event(); var time = e.Time - songStartTime; int timeStamp = Math.Max(secondsToSamples(time, (double)song.Tempo, (double)song.SampleRate), lastTimeStamp); songEvent.TimeStamp = secondsToSamples(time, (double)song.Tempo, (double)song.SampleRate); songEvent.Type = e.Type; songEvent.Note = e.Note; songEvent.Velocity = e.Velocity; track.Events.Add(songEvent); lastTimeStamp = timeStamp; } } // TODO: Clip all of this instead of just offsetting // adjust automation start times based on song start foreach (var track in song.Tracks) { foreach (var automation in track.Automations) { foreach (var point in automation.Points) { point.TimeStamp -= secondsToSamples(songStartTime, (double)song.Tempo, (double)song.SampleRate); } } } foreach (var kvp in projectTracksToSongTracks) { foreach (var projectReceive in trackReceives[kvp.Key]) { if (projectTracksToSongTracks.ContainsKey(projectReceive.SendingTrack)) { var receive = new Song.Receive(); receive.SendingTrackIndex = song.Tracks.IndexOf(projectTracksToSongTracks[projectReceive.SendingTrack]); receive.ReceivingChannelIndex = projectReceive.ReceivingChannelIndex; receive.Volume = (float)projectReceive.Volume; kvp.Value.Receives.Add(receive); } } } return(song); }
public Song Process(RenoiseSong project, ILog logger) { this.logger = logger; // hex lookup.. because reasons... for (int i = 0; i <= 255; i++) { hexLookUp.Add(i.ToString("X2"), (byte)i); } this.project = project; var song = new Song(); song.Tempo = (int)this.project.GlobalSongData.BeatsPerMin; song.SampleRate = 44100; secondsPerIndex = (double)song.Tempo * (double)this.project.GlobalSongData.LinesPerBeat; secondsPerIndex = 60 / secondsPerIndex; sampleRate = song.SampleRate; song.Length = GetSongLength(); var master = this.project.Tracks.Items.Where(track => track is SequencerMasterTrack).First(); trackReceives = new Dictionary <object, List <RnsReceive> >(); foreach (var projectTrack in this.project.Tracks.Items) { trackReceives.Add(projectTrack, new List <RnsReceive>()); } // send mapping foreach (var projectTrack in this.project.Tracks.Items) { string trackName = GetProp("Name", projectTrack).ToString(); object[] trackDevices = ((TrackFilterDeviceChain)GetProp("FilterDevices", projectTrack)).Devices.Items; var sends = new List <SendDevice>(); // get all send devices bool found = false; foreach (var device in trackDevices) { if (device is SendDevice) { found = true; sends.Add((SendDevice)device); } if (found && !(device is SendDevice)) { logger.WriteLine("WARNING: Track {0} has device {1} after send", trackName, device); } } foreach (var send in sends) { if (send.MuteSource && sends.IndexOf(send) != sends.Count - 1) { logger.WriteLine("WARNING: Track {0} has muted send which is not the last send in the chain", trackName); } if (send.IsActive.Value == 1 && send.SendAmount.Value > 0) { var sendTrack = GetSendTrack((int)send.DestSendTrack.Value); trackReceives[sendTrack].Add(new RnsReceive(projectTrack, 0, send.SendAmount.Value)); } else { logger.WriteLine("WARNING: Track {0} has disabled send", trackName); } } // track is not master, so find where it goes... if (projectTrack != master) { int routing = (int)GetProp("TrackRouting", projectTrack); if (routing == 0) { // routed to master if (!MutedSend(projectTrack)) // muted send so no actual output { var trackVolume = GetTrackVolume(trackDevices[0]); trackReceives[master].Add(new RnsReceive(projectTrack, 0, trackVolume)); } } else if (routing == -1) { // routed to group track if (!MutedSend(projectTrack)) // muted send so no actual output { var group = GetGroupTrack(projectTrack); var trackVolume = GetTrackVolume(trackDevices[0]); trackReceives[group].Add(new RnsReceive(projectTrack, 0, trackVolume)); } } else { // routed to specific soundcard output logger.WriteLine(string.Format("WARNING: Track {0} routing to soundcard?? WTF!", trackName)); } } } visitedTracks = new List <object>(); orderedTracks = new List <object>(); VisitTrack(master); GetInstruments(); var projectTracksToSongTracks = new Dictionary <object, Song.Track>(); foreach (var projectTrack in orderedTracks) { var track = ConvertTrack(this.project.Tracks.Items.ToList().IndexOf(projectTrack)); projectTracksToSongTracks.Add(projectTrack, track); song.Tracks.Add(track); } foreach (var kvp in projectTracksToSongTracks) { foreach (var projectReceive in trackReceives[kvp.Key]) { if (projectTracksToSongTracks.ContainsKey(projectReceive.SendingTrack)) { var receive = new Song.Receive(); receive.SendingTrackIndex = song.Tracks.IndexOf(projectTracksToSongTracks[projectReceive.SendingTrack]); receive.ReceivingChannelIndex = projectReceive.ReceivingChannelIndex; receive.Volume = (float)projectReceive.Volume; kvp.Value.Receives.Add(receive); } } } return(song); }