Audio track velocity editing in the sequencer.

This commit is contained in:
Johannes Findeisen 2026-11-06 21:10:48 +01:00
commit 896a7907d3
10 changed files with 292 additions and 6 deletions

View file

@ -1214,6 +1214,69 @@ int main(int argc, char **argv)
unlink("/tmp/xtc-workspace.xtc"); window.do_callback();
}
reset();
{
MainWindow window(false,""); window.show(); auto *s=timeline(&window);
char wave[4096]; CHECK(realpath("examples/projects/original-pluck.wav",wave));
CHECK(window.create_track(false)==XTC_OK && window.import_audio(wave)==XTC_OK);
uint64_t track=s->selected_track(); CHECK(s->expand_track(track,true));
CHECK(s->set_zoom(96)==XTC_OK && s->grid(960)==XTC_OK);
float base_l[256]{},base_r[256]{},edited_l[256]{},edited_r[256]{};
xtc_audio_plan *plan=nullptr;
CHECK(xtc_audio_plan_create(s->project(),48000,&plan)==XTC_OK);
CHECK(xtc_audio_plan_render_stereo(plan,1000,base_l,base_r,256)==XTC_OK); xtc_audio_plan_destroy(plan);
// An arbitrary off-grid position, with no MIDI notes, creates an audio level point.
int px=s->header_width()+37, top=28+56;
gesture(s,px,top+65,0,-15); // 2x gain at tick 370.
size_t count=0; xtc_project_automation_count(s->project(),&count); CHECK(count==1);
xtc_automation_point point{}; xtc_project_get_automation(s->project(),0,&point);
CHECK(point.track_id==track && point.tick==370 && point.parameter==XTC_AUTOMATION_GAIN && point.value==2.0f && !point.step);
CHECK(xtc_audio_plan_create(s->project(),48000,&plan)==XTC_OK);
CHECK(xtc_audio_plan_render_stereo(plan,1000,edited_l,edited_r,256)==XTC_OK); xtc_audio_plan_destroy(plan);
for(int i=0;i<256;++i) CHECK(std::fabs(edited_l[i]-base_l[i]*2)<1e-5f && std::fabs(edited_r[i]-base_r[i]*2)<1e-5f);
CHECK(window.undo(false)==XTC_OK); xtc_project_automation_count(s->project(),&count); CHECK(count==0);
CHECK(window.undo(true)==XTC_OK && s->track_expanded(track));
gesture(s,px,top+50,0,500); // Existing point clamps to silence.
xtc_project_get_automation(s->project(),0,&point); CHECK(point.tick==370 && point.value==0);
gesture(s,px,top+80,0,-500); // Existing point clamps to 400%.
xtc_project_get_automation(s->project(),0,&point); CHECK(point.value==4);
gesture(s,s->header_width()+61,top+65,0,0);
xtc_project_automation_count(s->project(),&count); CHECK(count==2);
// A pre-existing Hold point keeps its interpolation mode when dragged.
xtc_project_get_automation(s->project(),1,&point); point.step=1;
CHECK(xtc_project_set_automation(s->project(),&point)==XTC_OK);
gesture(s,s->header_width()+61,top+65,0,-15);
xtc_project_get_automation(s->project(),1,&point); CHECK(point.tick==610 && point.value==2 && point.step==1);
// Escape cancels a point at another arbitrary position.
int ox=Fl::e_x,oy=Fl::e_y,ok=Fl::e_keysym;
Fl::e_x=s->x()+s->header_width()+91; Fl::e_y=s->y()+top+50;
Fl::e_keysym=FL_Button+FL_LEFT_MOUSE; CHECK(s->handle(FL_PUSH)==1);
Fl::e_y+=10; CHECK(s->handle(FL_DRAG)==1);
Fl::e_keysym=FL_Escape; CHECK(s->handle(FL_KEYDOWN)==1);
xtc_project_automation_count(s->project(),&count); CHECK(count==2);
CHECK(window.save_project("/tmp/xtc-audio-velocity.xtc")==XTC_OK);
CHECK(window.new_project()==XTC_OK && window.open_project("/tmp/xtc-audio-velocity.xtc")==XTC_OK);
CHECK(s->expand_track(track,true));
xtc_project_get_automation(s->project(),0,&point); CHECK(point.value==4 && point.tick==370);
CHECK(s->set_zoom(96)==XTC_OK);
// Delete a point with the real right mouse gesture; undo restores it.
Fl::e_x=s->x()+px; Fl::e_y=s->y()+top+20;
Fl::e_keysym=FL_Button+FL_RIGHT_MOUSE; CHECK(s->handle(FL_PUSH)==1);
Fl::e_x=ox; Fl::e_y=oy; Fl::e_keysym=ok;
xtc_project_automation_count(s->project(),&count); CHECK(count==1);
CHECK(window.undo(false)==XTC_OK); xtc_project_automation_count(s->project(),&count); CHECK(count==2);
// Pinned headers and horizontal scrolling still map to timeline positions.
auto *scroll=dynamic_cast<Fl_Scroll *>(s->parent()); CHECK(scroll);
scroll->scroll_to(80,0); pump();
int screen_x=s->header_left()+s->header_width()+100;
uint64_t expected=static_cast<uint64_t>(screen_x-s->x()-s->header_width())*960/static_cast<unsigned int>(s->zoom_level());
gesture(s,screen_x-s->x(),top+50,0,0);
xtc_project_automation_count(s->project(),&count); CHECK(count==3);
bool found=false;
for(size_t i=0;i<count;++i) {xtc_project_get_automation(s->project(),i,&point); if(point.tick==expected && point.value==2) found=true;}
CHECK(found);
unlink("/tmp/xtc-audio-velocity.xtc"); window.do_callback();
}
reset();
{
MainWindow window(false,""); window.show(); auto *s=timeline(&window);
CHECK(window.create_track(true)==XTC_OK);