@@ -179,38 +179,40 @@ void SamplerController::setSelectedPadHpfCutoff(double cutoff)
179179 }
180180}
181181
182+ SamplerController::OffsetParts SamplerController::splitSeconds (double seconds)
183+ {
184+ // Rounded to whole milliseconds before it is split, not floored: an offset is stored as a
185+ // fraction of a minute in a float, which does not land exactly on the second it was set to, and
186+ // flooring a value a hair short of one reads it as no seconds and a thousand milliseconds.
187+ const auto milliseconds = std::llround (std::max (0.0 , seconds) * 1000.0 );
188+ return { static_cast <int >(milliseconds / 1000 ), static_cast <int >(milliseconds % 1000 ) };
189+ }
190+
182191int SamplerController::selectedPadStartOffsetSeconds () const
183192{
184- if (!m_sampler || m_selectedPad < 0 ) {
185- return 0 ;
186- }
187- return static_cast <int >(m_sampler->sampleStartOffset (static_cast <uint8_t >(noteForPad (m_selectedPad))));
193+ const auto note = selectedNote ();
194+ return note ? splitSeconds (m_sampler->sampleStartOffset (*note)).seconds : 0 ;
188195}
189196
190197void SamplerController::setSelectedPadStartOffsetSeconds (int seconds)
191198{
192- if (m_sampler && m_selectedPad >= 0 ) {
193- const double currentOffset = m_sampler->sampleStartOffset (static_cast <uint8_t >(noteForPad (m_selectedPad)));
194- const double milliseconds = (currentOffset - std::floor (currentOffset)) * 1000.0 ;
195- m_sampler->setSampleStartOffset (static_cast <uint8_t >(noteForPad (m_selectedPad)), static_cast <double >(seconds) + milliseconds / 1000.0 );
199+ if (const auto note = selectedNote (); note) {
200+ const auto current = splitSeconds (m_sampler->sampleStartOffset (*note));
201+ m_sampler->setSampleStartOffset (*note, seconds + current.milliseconds / 1000.0 );
196202 }
197203}
198204
199205int SamplerController::selectedPadStartOffsetMilliseconds () const
200206{
201- if (!m_sampler || m_selectedPad < 0 ) {
202- return 0 ;
203- }
204- const double offset = m_sampler->sampleStartOffset (static_cast <uint8_t >(noteForPad (m_selectedPad)));
205- return static_cast <int >(std::round ((offset - std::floor (offset)) * 1000.0 ));
207+ const auto note = selectedNote ();
208+ return note ? splitSeconds (m_sampler->sampleStartOffset (*note)).milliseconds : 0 ;
206209}
207210
208211void SamplerController::setSelectedPadStartOffsetMilliseconds (int milliseconds)
209212{
210- if (m_sampler && m_selectedPad >= 0 ) {
211- const double currentOffset = m_sampler->sampleStartOffset (static_cast <uint8_t >(noteForPad (m_selectedPad)));
212- const double seconds = std::floor (currentOffset);
213- m_sampler->setSampleStartOffset (static_cast <uint8_t >(noteForPad (m_selectedPad)), seconds + static_cast <double >(milliseconds) / 1000.0 );
213+ if (const auto note = selectedNote (); note) {
214+ const auto current = splitSeconds (m_sampler->sampleStartOffset (*note));
215+ m_sampler->setSampleStartOffset (*note, current.seconds + milliseconds / 1000.0 );
214216 }
215217}
216218
@@ -225,83 +227,61 @@ std::optional<uint8_t> SamplerController::selectedNote() const
225227int SamplerController::selectedPadEndOffsetSeconds () const
226228{
227229 const auto note = selectedNote ();
228- if (!note) {
229- return 0 ;
230- }
231- return static_cast <int >(std::floor (m_sampler->sampleEndOffset (*note)));
230+ return note ? splitSeconds (m_sampler->sampleEndOffset (*note)).seconds : 0 ;
232231}
233232
234233void SamplerController::setSelectedPadEndOffsetSeconds (int seconds)
235234{
236- const auto note = selectedNote ();
237- if (!note) {
238- return ;
235+ if (const auto note = selectedNote (); note) {
236+ const auto current = splitSeconds (m_sampler->sampleEndOffset (*note));
237+ m_sampler->setSampleEndOffset (*note, seconds + current.milliseconds / 1000.0 );
238+ emit selectedPadEndOffsetChanged ();
239239 }
240- const double current = m_sampler->sampleEndOffset (*note);
241- m_sampler->setSampleEndOffset (*note, static_cast <double >(seconds) + (current - std::floor (current)));
242- emit selectedPadEndOffsetChanged ();
243240}
244241
245242int SamplerController::selectedPadEndOffsetMilliseconds () const
246243{
247244 const auto note = selectedNote ();
248- if (!note) {
249- return 0 ;
250- }
251- const double offset = m_sampler->sampleEndOffset (*note);
252- return static_cast <int >(std::round ((offset - std::floor (offset)) * 1000.0 ));
245+ return note ? splitSeconds (m_sampler->sampleEndOffset (*note)).milliseconds : 0 ;
253246}
254247
255248void SamplerController::setSelectedPadEndOffsetMilliseconds (int milliseconds)
256249{
257- const auto note = selectedNote ();
258- if (!note) {
259- return ;
250+ if (const auto note = selectedNote (); note) {
251+ const auto current = splitSeconds (m_sampler->sampleEndOffset (*note));
252+ m_sampler->setSampleEndOffset (*note, current.seconds + milliseconds / 1000.0 );
253+ emit selectedPadEndOffsetChanged ();
260254 }
261- const double current = m_sampler->sampleEndOffset (*note);
262- m_sampler->setSampleEndOffset (*note, std::floor (current) + static_cast <double >(milliseconds) / 1000.0 );
263- emit selectedPadEndOffsetChanged ();
264255}
265256
266257int SamplerController::selectedPadLoopStartSeconds () const
267258{
268259 const auto note = selectedNote ();
269- if (!note) {
270- return 0 ;
271- }
272- return static_cast <int >(std::floor (m_sampler->sampleLoopStart (*note)));
260+ return note ? splitSeconds (m_sampler->sampleLoopStart (*note)).seconds : 0 ;
273261}
274262
275263void SamplerController::setSelectedPadLoopStartSeconds (int seconds)
276264{
277- const auto note = selectedNote ();
278- if (!note) {
279- return ;
265+ if (const auto note = selectedNote (); note) {
266+ const auto current = splitSeconds (m_sampler->sampleLoopStart (*note));
267+ m_sampler->setSampleLoopStart (*note, seconds + current.milliseconds / 1000.0 );
268+ emit selectedPadLoopStartChanged ();
280269 }
281- const double current = m_sampler->sampleLoopStart (*note);
282- m_sampler->setSampleLoopStart (*note, static_cast <double >(seconds) + (current - std::floor (current)));
283- emit selectedPadLoopStartChanged ();
284270}
285271
286272int SamplerController::selectedPadLoopStartMilliseconds () const
287273{
288274 const auto note = selectedNote ();
289- if (!note) {
290- return 0 ;
291- }
292- const double offset = m_sampler->sampleLoopStart (*note);
293- return static_cast <int >(std::round ((offset - std::floor (offset)) * 1000.0 ));
275+ return note ? splitSeconds (m_sampler->sampleLoopStart (*note)).milliseconds : 0 ;
294276}
295277
296278void SamplerController::setSelectedPadLoopStartMilliseconds (int milliseconds)
297279{
298- const auto note = selectedNote ();
299- if (!note) {
300- return ;
280+ if (const auto note = selectedNote (); note) {
281+ const auto current = splitSeconds (m_sampler->sampleLoopStart (*note));
282+ m_sampler->setSampleLoopStart (*note, current.seconds + milliseconds / 1000.0 );
283+ emit selectedPadLoopStartChanged ();
301284 }
302- const double current = m_sampler->sampleLoopStart (*note);
303- m_sampler->setSampleLoopStart (*note, std::floor (current) + static_cast <double >(milliseconds) / 1000.0 );
304- emit selectedPadLoopStartChanged ();
305285}
306286
307287double SamplerController::selectedPadTune () const
@@ -432,6 +412,16 @@ void SamplerController::setSelectedPadLoop(bool loop)
432412 const auto note = selectedNote ();
433413 if (note && m_sampler->sampleLoop (*note) != loop) {
434414 m_sampler->setSampleLoop (*note, loop);
415+ // A loop point at the beginning of the range sits underneath the start marker, where it can
416+ // be neither seen nor taken hold of. Turning looping on drops it in the middle of the range
417+ // instead, which is somewhere to drag it from. A point the pad already carries is its own.
418+ if (loop && m_sampler->sampleLoopStart (*note) <= 0.0 ) {
419+ const auto range = m_sampler->sampleDuration (*note) - m_sampler->sampleStartOffset (*note) - m_sampler->sampleEndOffset (*note);
420+ if (range > 0.0 ) {
421+ m_sampler->setSampleLoopStart (*note, range / 2.0 );
422+ emit selectedPadLoopStartChanged ();
423+ }
424+ }
435425 emit selectedPadLoopChanged ();
436426 }
437427}
0 commit comments