Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 6 additions & 124 deletions sources/Application/Instruments/SampleInstrument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ SampleInstrument::SampleInstrument()
crush_(FourCC::SampleInstrumentCrush, 16),
drive_(FourCC::SampleInstrumentCrushVolume, 0xFF),
downsample_(FourCC::SampleInstrumentDownsample, 0),
slices_(FourCC::SampleInstrumentSlices, -1),
rootNote_(FourCC::SampleInstrumentRootNote, 60),
fineTune_(FourCC::SampleInstrumentFineTune, 0x7F),
pan_(FourCC::SampleInstrumentPan, 0x7F),
Expand Down Expand Up @@ -72,7 +71,6 @@ SampleInstrument::SampleInstrument()
variables_.insert(variables_.end(), &crush_);
variables_.insert(variables_.end(), &drive_);
variables_.insert(variables_.end(), &downsample_);
variables_.insert(variables_.end(), &slices_);
variables_.insert(variables_.end(), &rootNote_);
variables_.insert(variables_.end(), &fineTune_);
variables_.insert(variables_.end(), &pan_);
Expand Down Expand Up @@ -149,96 +147,9 @@ bool SampleInstrument::Start(int channel, unsigned char midinote,

rp->pan_ = rp->basePan_ = i2fp(pan_.GetInt());

// TODO (democloid): We have 3 potential differnt modes, single sample
// multisample based on source file (CUEs not currently supported) which would
// be evaluated on the source material and use the IsMulti call on the source
// Explicit slicing, we tell how we want the sample file to be interpreted
int32_t slicedStart = 0;
if (!source_->IsMulti()) {
// Check if slices are disabled or set to an invalid value
// -1, 0, or 1 all mean no slices
if (slices_.GetInt() <= 1) {
// single sample mode (no slices)
rp->rendLoopStart_ = loopStart_.GetInt();
rp->rendLoopEnd_ = loopEnd_.GetInt();

// If end is 0 or negative, use the full sample size
if (rp->rendLoopEnd_ <= 0) {
rp->rendLoopEnd_ = GetSampleSize(channel);
}
} else {
// sliced mode
uint32_t totalSize = GetSampleSize(channel);
uint8_t numSlices = (uint8_t)slices_.GetInt();

// Get user-defined start and end points
uint32_t userStart = start_.GetInt();
uint32_t userEnd = loopEnd_.GetInt();

// Ensure we have enough range for the number of slices
// End point should be at least (numSlices) more than start point
if (userEnd <= userStart + numSlices) {
// just dont play anything in this case
return false;
}

// Calculate the effective sample range to slice
uint32_t effectiveStart = userStart;
uint32_t effectiveEnd = userEnd;
uint32_t effectiveSize = effectiveEnd - effectiveStart;

// Ensure we have a valid size
if (effectiveSize <= 0) {
return false;
}

// Ensure at least 1 sample per slice
uint32_t sliceSize = effectiveSize / numSlices;
if (sliceSize <= 0) {
return false;
}

int note = rp->midiNote_;
int rootNoteVal = rootNote_.GetInt();
int8_t sliceNum = note - rootNoteVal;
Trace::Debug("SLICES: Midi note %i Root %i Slice Number: %i", note,
rootNoteVal, sliceNum);

if ((sliceNum < 0) || (sliceNum >= numSlices)) {
Trace::Debug("SLICES: Out of range, discarded");
return false;
}

// Calculate slice boundaries within the effective range
uint32_t sliceStart = effectiveStart + (sliceNum * sliceSize);
uint32_t sliceEnd = sliceStart + sliceSize;

// Ensure slice boundaries are within sample bounds
if (sliceEnd > totalSize) {
sliceEnd = totalSize;
}

// Set playback points for this slice
slicedStart = sliceStart;

// Make sure start point doesn't exceed sample end
if (sliceStart >= effectiveEnd) {
Trace::Debug("SLICES: Start point exceeds sample end");
return false;
}

// For slices, we always use one-shot mode regardless of the loop mode
// setting This overrides any loop mode setting when using slices
loopMode_.SetInt(SILM_ONESHOT);
Trace::Debug("SLICES: Enforcing one-shot mode for slices");

// Set the boundaries for one-shot playback of this slice
rp->rendLoopStart_ = sliceStart;
rp->rendLoopEnd_ = sliceEnd;

Trace::Debug("SLICES: Slice %i boundaries: %i to %i (one-shot mode)",
sliceNum, sliceStart, sliceEnd);
}
rp->rendLoopStart_ = loopStart_.GetInt();
rp->rendLoopEnd_ = loopEnd_.GetInt();
} else {
long start = source_->GetLoopStart(rp->midiNote_);
if (start > 0) {
Expand Down Expand Up @@ -274,20 +185,8 @@ bool SampleInstrument::Start(int channel, unsigned char midinote,
// if instrument sampled below 44.1Khz, should
// travel slower in sample

// Set the initial playback position to the slice start
rp->rendFirst_ = slicedStart;
rp->rendFirst_ = start_.GetInt();
rp->position_ = float(rp->rendFirst_);

// Ensure position stays within valid boundaries
if (rp->position_ < 0) {
rp->position_ = 0;
}

// For non-oneshot modes, ensure we start at loop start if needed
if (loopMode_.GetInt() != SILM_ONESHOT &&
rp->position_ < float(rp->rendLoopStart_)) {
rp->position_ = float(rp->rendLoopStart_);
}
rp->baseSpeed_ = fl2fp(source_->GetSampleRate(rp->midiNote_) / driverRate);
rp->reverse_ = (rp->rendLoopEnd_ < rp->position_);

Expand Down Expand Up @@ -874,25 +773,8 @@ bool SampleInstrument::Render(int channel, fixed *buffer, int size,
rp->reverse_ = rpReverse;

// Update final sample position
if (input && wavbuf) {
rp->position_ =
(((char *)input) - wavbuf) / (2 * channelCount) + fp2fl(fpPos);

// Safety check for valid position
if (rp->position_ < 0) {
rp->position_ = 0;
}

// Ensure position stays within slice boundaries for sliced mode
if (slices_.GetInt() > 0 && !source_->IsMulti()) {
// If we've gone past the slice end, reset to loop start for looping
// modes
if (loopMode_.GetInt() != SILM_ONESHOT &&
rp->position_ >= float(rp->rendLoopEnd_)) {
rp->position_ = float(rp->rendLoopStart_);
}
}
}
rp->position_ =
(((char *)input) - wavbuf) / (2 * channelCount) + fp2fl(fpPos);

somethingToMix = true;
}
Expand Down Expand Up @@ -1324,4 +1206,4 @@ bool SampleInstrument::IsMulti() { return source_->IsMulti(); }
void SampleInstrument::EnableDownsamplingLegacy() {
useDirtyDownsampling_ = true;
Trace::Log("CONFIG", "Enabling downsampling legacy");
}
}
3 changes: 1 addition & 2 deletions sources/Application/Instruments/SampleInstrument.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class SampleInstrument : public I_Instrument, I_Observer {
void doKRateUpdate(int channel);

private:
etl::list<Variable *, 21> variables_;
etl::list<Variable *, 20> variables_;

SoundSource *source_;
static struct renderParams renderParams_[SONG_CHANNEL_COUNT];
Expand All @@ -88,7 +88,6 @@ class SampleInstrument : public I_Instrument, I_Observer {
Variable crush_;
Variable drive_;
Variable downsample_;
Variable slices_;
Variable rootNote_;
Variable fineTune_;
Variable pan_;
Expand Down
2 changes: 1 addition & 1 deletion sources/Application/Instruments/WavFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,4 @@ void WavFile::Close() {
readBufferSize_ = 0;
};

int WavFile::GetRootNote(int note) { return 60; }
int WavFile::GetRootNote(int note) { return 60; }
2 changes: 1 addition & 1 deletion sources/Application/Instruments/WavFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ class WavFile : public SoundSource {
static bool initChunkSize_;
static unsigned char readBuffer_[BUFFER_SIZE];
};
#endif
#endif
63 changes: 5 additions & 58 deletions sources/Application/Views/InstrumentView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ void InstrumentView::onInstrumentChange() {
refreshInstrumentFields();
};

void InstrumentView::refreshInstrumentFields(FourCC focus) {
void InstrumentView::refreshInstrumentFields() {
for (auto &f : intVarField_) {
f.RemoveObserver(*this);
}
Expand All @@ -167,7 +167,7 @@ void InstrumentView::refreshInstrumentFields(FourCC focus) {

// first put back the type field as its shown on *all* instrument types
fieldList_.insert(fieldList_.end(), &(*typeIntVarField_.rbegin()));
lastFocusID_ = focus;
lastFocusID_ = FourCC::VarInstrumentType;

// Re-add the action fields for export and import only if not IT_NONE
if (instrumentType_.GetInt() != IT_NONE) {
Expand Down Expand Up @@ -269,15 +269,6 @@ void InstrumentView::fillSampleParameters() {
intVarField_.emplace_back(position, *v, "pan: %2.2X", 0, 0xFE, 1, 0x10);
fieldList_.insert(fieldList_.end(), &(*intVarField_.rbegin()));

position._x += 10;
Variable *s = instrument->FindVariable(FourCC::SampleInstrumentSlices);
intVarOffField_.emplace_back(position, *s, "Slices: %d", 2, 64, 1, 8);
fieldList_.insert(fieldList_.end(), &(*intVarOffField_.rbegin()));

// add observer
(*intVarOffField_.rbegin()).AddObserver(*this);

position._x -= 10;
position._y += 1;
v = instrument->FindVariable(FourCC::SampleInstrumentRootNote);
noteVarField_.emplace_back(position, *v, "root note: %s", 0, 0x7F, 1, 0x0C);
Expand Down Expand Up @@ -342,39 +333,20 @@ void InstrumentView::fillSampleParameters() {

position._y += 1;
v = instrument->FindVariable(FourCC::SampleInstrumentStart);
// Calculate max value for start field - use full sample size if no slices
int maxStartValue = instrument->GetSampleSize() - 1;
if (s->GetInt() > 0) {
// If slices are enabled, we still allow editing the full range
// The actual slice boundaries will be enforced during playback
}
bigHexVarField_.emplace_back(position, *v, 7, "start: %7.7X", 0,
maxStartValue, 16);
instrument->GetSampleSize() - 1, 16);
fieldList_.insert(fieldList_.end(), &(*bigHexVarField_.rbegin()));

position._y += 1;
v = instrument->FindVariable(FourCC::SampleInstrumentLoopStart);
// Calculate max value for loop start field - use full sample size if no
// slices
int maxLoopStartValue = instrument->GetSampleSize() - 1;
if (s->GetInt() > 0) {
// If slices are enabled, we still allow editing the full range
// The actual slice boundaries will be enforced during playback
}
bigHexVarField_.emplace_back(position, *v, 7, "loop start: %7.7X", 0,
maxLoopStartValue, 16);
instrument->GetSampleSize() - 1, 16);
fieldList_.insert(fieldList_.end(), &(*bigHexVarField_.rbegin()));

position._y += 1;
v = instrument->FindVariable(FourCC::SampleInstrumentEnd);
// Calculate max value for loop end field - use full sample size if no slices
int maxLoopEndValue = instrument->GetSampleSize() - 1;
if (s->GetInt() > 0) {
// If slices are enabled, we still allow editing the full range
// The actual slice boundaries will be enforced during playback
}
bigHexVarField_.emplace_back(position, *v, 7, "loop end: %7.7X", 0,
maxLoopEndValue, 16);
instrument->GetSampleSize() - 1, 16);
fieldList_.insert(fieldList_.end(), &(*bigHexVarField_.rbegin()));

v = instrument->FindVariable(FourCC::SampleInstrumentTableAutomation);
Expand Down Expand Up @@ -988,22 +960,6 @@ void InstrumentView::Update(Observable &o, I_ObservableData *data) {
SetChanged();
NotifyObservers(&ve);
} break;
case FourCC::SampleInstrumentSlices: {
// We are assuming we can only get here when instrument is Sample, safe?
Trace::Debug("INSTRUMENTVIEW", "slice changed, redraw!");
I_Instrument *instrument = getInstrument();
// In slice change, reset markers for start and loop start
Variable *ls = instrument->FindVariable(FourCC::SampleInstrumentStart);
ls->SetInt(0, true);
ls = instrument->FindVariable(FourCC::SampleInstrumentLoopStart);
ls->SetInt(0, true);
Variable *slices = instrument->FindVariable(FourCC::SampleInstrumentSlices);
ls = instrument->FindVariable(FourCC::SampleInstrumentEnd);
ls->SetInt((((SampleInstrument *)instrument)->GetSampleSize() - 1) /
slices->GetInt(),
true);
refreshInstrumentFields(FourCC::SampleInstrumentSlices);
} break;
case FourCC::MidiInstrumentProgram: {
// When program value changes, send a MIDI Program Change message
I_Instrument *instr = getInstrument();
Expand Down Expand Up @@ -1140,12 +1096,3 @@ void InstrumentView::handleInstrumentExport() {
}
}
}

// Redraw all UI fields to reflect updated variable values
void InstrumentView::redrawAllFields() {
for (auto field : fieldList_) {
if (field) {
field->Draw(w_);
}
}
}
8 changes: 3 additions & 5 deletions sources/Application/Views/InstrumentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,11 @@ class InstrumentView : public FieldView, public I_Observer {
void fillNoneParameters();
I_Instrument *getInstrument();
void Update(Observable &o, I_ObservableData *d);
void refreshInstrumentFields(FourCC focus = FourCC::VarInstrumentType);
void refreshInstrumentFields();
void addNameTextField(I_Instrument *instr, GUIPoint &position);
void handleInstrumentExport();

private:
// Redraw all fields to reflect updated variable values
void redrawAllFields();
Project *project_;
FourCC lastFocusID_;
WatchedVariable instrumentType_;
Expand All @@ -58,11 +56,11 @@ class InstrumentView : public FieldView, public I_Observer {

etl::vector<UIIntVarField, 1> typeIntVarField_;
etl::vector<UIActionField, 2> actionField_;
etl::vector<UIIntVarField, 39> intVarField_;
etl::vector<UIIntVarField, 40> intVarField_;
etl::vector<UINoteVarField, 1> noteVarField_;
etl::vector<UIStaticField, 4> staticField_;
etl::vector<UIBigHexVarField, 4> bigHexVarField_;
etl::vector<UIIntVarOffField, 2> intVarOffField_;
etl::vector<UIIntVarOffField, 1> intVarOffField_;
etl::vector<UIBitmaskVarField, 3> bitmaskVarField_;
etl::vector<UITextField<MAX_INSTRUMENT_NAME_LENGTH>, 1> nameTextField_;
etl::vector<InstrumentNameVariable, 1> nameVariables_;
Expand Down
1 change: 0 additions & 1 deletion sources/Foundation/Types/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ struct FourCC {
ETL_ENUM_TYPE(SampleInstrumentEnd, "end")
ETL_ENUM_TYPE(SampleInstrumentTable, "table")
ETL_ENUM_TYPE(SampleInstrumentTableAutomation, "table automation")
ETL_ENUM_TYPE(SampleInstrumentSlices, "Slices")
ETL_ENUM_TYPE(MidiInstrumentChannel, "channel")
ETL_ENUM_TYPE(InstrumentName, "name")
ETL_ENUM_TYPE(MidiInstrumentName, "midi name")
Expand Down