| 112 | } |
| 113 | |
| 114 | AudioWaveformData AudioWaveformer::ApplyKeyframes(const AudioWaveformData& base, |
| 115 | const Keyframe* time_keyframe, |
| 116 | const Keyframe* volume_keyframe, |
| 117 | const Fraction& project_fps, |
| 118 | const Fraction& source_fps, |
| 119 | int source_channels, |
| 120 | int num_per_second, |
| 121 | int channel, |
| 122 | bool normalize) { |
| 123 | AudioWaveformData data; |
| 124 | if (num_per_second <= 0) { |
| 125 | return data; |
| 126 | } |
| 127 | |
| 128 | double project_fps_value = project_fps.ToDouble(); |
| 129 | double source_fps_value = source_fps.ToDouble(); |
| 130 | if (project_fps_value <= 0.0 || source_fps_value <= 0.0) { |
| 131 | return data; |
| 132 | } |
| 133 | |
| 134 | if (channel != -1 && (channel < 0 || channel >= source_channels)) { |
| 135 | return data; |
| 136 | } |
| 137 | |
| 138 | size_t base_total = base.max_samples.size(); |
| 139 | if (base_total == 0) { |
| 140 | return data; |
| 141 | } |
| 142 | |
| 143 | // Determine output duration from time curve (if any). Time curves are in project-frame domain. |
| 144 | int64_t output_frames = 0; |
| 145 | if (time_keyframe && time_keyframe->GetCount() > 0) { |
| 146 | output_frames = time_keyframe->GetLength(); |
| 147 | } |
| 148 | if (output_frames <= 0) { |
| 149 | // Default to source duration derived from base waveform length |
| 150 | double source_duration = static_cast<double>(base_total) / static_cast<double>(num_per_second); |
| 151 | output_frames = static_cast<int64_t>(std::llround(source_duration * project_fps_value)); |
| 152 | } |
| 153 | double output_duration_seconds = static_cast<double>(output_frames) / project_fps_value; |
| 154 | int total_samples = static_cast<int>(std::ceil(output_duration_seconds * num_per_second)); |
| 155 | |
| 156 | if (total_samples <= 0) { |
| 157 | return data; |
| 158 | } |
| 159 | |
| 160 | data.resize(total_samples); |
| 161 | data.zero(total_samples); |
| 162 | |
| 163 | for (int i = 0; i < total_samples; ++i) { |
| 164 | double out_time = static_cast<double>(i) / static_cast<double>(num_per_second); |
| 165 | // Time keyframes are defined in project-frame domain; evaluate using project frames |
| 166 | double project_frame = out_time * project_fps_value; |
| 167 | double mapped_project_frame = time_keyframe ? time_keyframe->GetValue(project_frame) : project_frame; |
| 168 | // Convert mapped project frame to seconds (project FPS), then to waveform index |
| 169 | double source_time = mapped_project_frame / project_fps_value; |
| 170 | double source_index = source_time * static_cast<double>(num_per_second); |
| 171 | |