Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Various additions
Fix regression caused in https://github.com/djdiskmachine/LittleGPTracker/pull/245
Fix introduced microtonality for single cycle osc, thank you @INFU-AV <3
Purge samples actually purges samples [author: maks](https://github.com/xiphonics/picoTracker/pull/313)
Clear SoundFonts on SamplePool reset

1.6.0-bacon11
Slices decoupled from loop mode
Expand Down
2 changes: 1 addition & 1 deletion docs/wiki/What-is-LittlePiggyTracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ After that you can copy additional wavs to the lgptRoot/lgptProject/samples dire

**Use 8 or 16 Bit wav files, any sampling frequency, mono or stereo**. 8bit samples are converted to 16bit at load time for compatibility with the engine (you can save space in storage but not in RAM).

**Piggy now supports .sf2 Soundfonts. You must add these by hand to your SAMPLES directory, use PROGRAM CHANGE commands to load different patches. Loop points are automatically loaded, but you'll need to make VOLM setting to adjust decay.**
**Piggy now supports .sf2 Soundfonts.** You must add these by hand to your SAMPLES directory, use PROGRAM CHANGE commands to load different patches. Loop points are automatically loaded, but you'll need to make VOLM setting to adjust decay. By default, at most 3 are loaded per project; this limit may be increased by recompiling LittleGPTracker with the compiler flag `-DMAXLOADEDBANKS=X`, where `X` is the desired limit.

## New project

Expand Down
15 changes: 14 additions & 1 deletion sources/Application/AppWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ void AppWindow::LoadProject(const Path &p) {

SamplePool *pool = SamplePool::GetInstance();

pool->Load();
unsigned int load_result = pool->Load();

Project *project = new Project();

Expand Down Expand Up @@ -397,6 +397,19 @@ void AppWindow::LoadProject(const Path &p) {
_songView->DoModal(mb);
}

// Report on sample & SoundFont load fails
if (load_result) {
const char *err_str = (load_result == SLOAD_ERR_MAX_SAMPLES) ? "Maximum number of samples exceeded"
: (load_result == SLOAD_ERR_MAX_SOUNDFONTS) ? "Maximum number of SoundFonts exceeded"
: (load_result == SLOAD_ERR_MAX_SAMPLES | SLOAD_ERR_MAX_SOUNDFONTS) ? "Maximum number of samples and SoundFonts exceeded"
: (load_result == SLOAD_ERR_INVALID_DIR) ? "Sample directory could not be opened"
: "Unknown error loading sample pool";
Trace::Error(err_str) ;
MessageBox *mb =
new MessageBox(*_currentView, err_str);
_currentView->DoModal(mb);
}

Redraw();
}

Expand Down
220 changes: 128 additions & 92 deletions sources/Application/Instruments/SamplePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,36 @@ void SamplePool::Reset() {
SoundFontManager::GetInstance()->Reset() ;
} ;

void SamplePool::Load() {
/*
Returns an element of
{SLOAD_OK, SLOAD_ERR_INVALID_DIR, SLOAD_ERR_MAX_SAMPLES,
SLOAD_ERR_MAX_SOUNDFONTS, SLOAD_ERR_MAX_SAMPLES | SLOAD_ERR_MAX_SOUNDFONTS}.
*/
unsigned int SamplePool::Load() {

Path sampleDir("samples:");
Path sampleDir("samples:");

I_Dir *dir=FileSystem::GetInstance()->Open(sampleDir.GetPath().c_str()) ;
if (!dir) {
return ;
}
I_Dir *dir = FileSystem::GetInstance()->Open(sampleDir.GetPath().c_str());
if (!dir) {
return SLOAD_ERR_INVALID_DIR;
}

unsigned int result = SLOAD_OK;

// First, find all wav files
// First, find all wav files

dir->GetContent("*.wav") ;
IteratorPtr<Path> it(dir->GetIterator()) ;
dir->GetContent("*.wav");
IteratorPtr<Path> it(dir->GetIterator()) ;
count_=0 ;

for(it->Begin();!it->IsDone();it->Next()) {
Path &path=it->CurrentItem() ;
Trace::Log("Load", "%s", path.GetCanonicalPath().c_str());
loadSample(path.GetPath().c_str()) ;
if (count_==MAX_PIG_SAMPLES) {
Trace::Error("Warning maximum sample count reached") ;
break ;
result |= SLOAD_ERR_MAX_SAMPLES;
Trace::Error("Warning maximum sample count reached");
break;
} ;

} ;
Expand All @@ -72,17 +80,26 @@ void SamplePool::Load() {

dir->GetContent("*.sf2") ;
IteratorPtr<Path> it2(dir->GetIterator()) ;
int sf_idx = 0;

for(it2->Begin();!it2->IsDone();it2->Next()) {
Path &path=it2->CurrentItem() ;
loadSoundFont(path.GetPath().c_str()) ;
} ;
for (it2->Begin(); !it2->IsDone(); it2->Next(), sf_idx++) {
Path &path=it2->CurrentItem() ;
Trace::Log("Load", "%s", path.GetCanonicalPath().c_str());
loadSoundFont(path.GetPath().c_str()) ;
if (sf_idx == MAX_SOUNDFONTS) {
result |= SLOAD_ERR_MAX_SOUNDFONTS;
Trace::Error("Warning maximum soundfont count reached");
break;
} ;
};

delete dir ;
delete dir;

// now sort the samples
// now sort the samples
Sort();
} ;

return result;
};

void SamplePool::Sort() {
int rest=count_;
Expand Down Expand Up @@ -124,41 +141,51 @@ int SamplePool::GetNameListSize() {
return count_ ;
} ;

bool SamplePool::loadSample(const char *path) {

if (count_==MAX_PIG_SAMPLES) return false ;

Path sPath(path) ;
Status::Set("Loading %s",sPath.GetName().c_str()) ;
Trace::Log("loadSample", "%s", path);

Path wavPath(path);
WavFile *wave=WavFile::Open(path) ;
if (wave) {
wav_[count_]=wave ;
const std::string name=wavPath.GetName() ;
names_[count_]=(char*)SYS_MALLOC(name.length()+1) ;
strcpy(names_[count_],name.c_str()) ;
count_++ ;
wave->GetBuffer(0,wave->GetSize(-1)) ;
wave->Close() ;
return true ;
} else {
Trace::Error("Failed to load samples %s",wavPath.GetName().c_str()) ;
return false ;
}
/*
Returns an element of
{SLOAD_OK, SLOAD_ERR_MAX_SAMPLES, SLOAD_ERR_INPUT_FILE}.
*/
int SamplePool::loadSample(const char *path) {

if (count_==MAX_PIG_SAMPLES) return SLOAD_ERR_MAX_SAMPLES ;

Path sPath(path) ;
Status::Set("Loading %s", sPath.GetName().c_str());
Trace::Log("loadSample", "%s", path);

Path wavPath(path);
WavFile *wave = WavFile::Open(path);
if (wave) {
wav_[count_] = wave;
const std::string name = wavPath.GetName();
names_[count_] = (char *)SYS_MALLOC(name.length() + 1);
strcpy(names_[count_], name.c_str());
count_++;
wave->GetBuffer(0, wave->GetSize(-1));
wave->Close();
return SLOAD_OK;
} else {
Trace::Error("Failed to load samples %s", wavPath.GetName().c_str());
return SLOAD_ERR_INPUT_FILE;
}
}

#define IMPORT_CHUNK_SIZE 1000

/*
Returns a nonnegative int or an element of
{-SLOAD_ERR_INVALID_DIR, -SLOAD_ERR_INPUT_FILE, -SLOAD_ERR_MAX_SAMPLES,
-SLOAD_ERR_MAX_SOUNDFONTS}.
*/
int SamplePool::ImportSample(Path &path) {

if (count_==MAX_PIG_SAMPLES) return -1 ;
if (count_ == MAX_PIG_SAMPLES)
return -SLOAD_ERR_MAX_SAMPLES;

// construct target path
// construct target path

std::string dpath="samples:" ;
dpath+=path.GetName() ;
std::string dpath = "samples:";
dpath+=path.GetName() ;
Path dstPath(dpath.c_str()) ;

// Opens files
Expand All @@ -167,23 +194,23 @@ int SamplePool::ImportSample(Path &path) {
if (!fin) {
Trace::Error("Failed to open input file %s",
path.GetCanonicalPath().c_str());
return -1;
return -SLOAD_ERR_INPUT_FILE;
};
fin->Seek(0,SEEK_END) ;
long size=fin->Tell() ;
fin->Seek(0, SEEK_END);
long size=fin->Tell() ;
fin->Seek(0,SEEK_SET) ;

I_File *fout=FileSystem::GetInstance()->Open(dstPath.GetPath().c_str(),"w") ;
if (!fout) {
fin->Close() ;
delete (fin) ;
return -1 ;
delete (fin);
return -SLOAD_ERR_OUTPUT_FILE ;
} ;

// copy file to current project
// copy file to current project

char buffer[IMPORT_CHUNK_SIZE] ;
while (size>0) {
char buffer[IMPORT_CHUNK_SIZE];
while (size>0) {
int count=(size>IMPORT_CHUNK_SIZE)?IMPORT_CHUNK_SIZE:size ;
fin->Read(buffer,1,count) ;
fout->Write(buffer,1,count) ;
Expand All @@ -195,16 +222,17 @@ int SamplePool::ImportSample(Path &path) {
delete(fin) ;
delete(fout) ;

// now load the sample

bool status=loadSample(dstPath.GetPath().c_str()) ;
// now load the sample
int status = dstPath.Matches("*.wav")
? loadSample(dstPath.GetPath().c_str())
: loadSoundFont(dstPath.GetPath().c_str());

SetChanged() ;
SamplePoolEvent ev ;
SetChanged();
SamplePoolEvent ev ;
ev.index_=count_-1 ;
ev.type_=SPET_INSERT ;
NotifyObservers(&ev) ;
return status?(count_-1):-1 ;
NotifyObservers(&ev);
return !status ?(count_-1):(-status) ;
};

bool SamplePool::IsImported(std::string name) {
Expand Down Expand Up @@ -302,49 +330,57 @@ void SamplePool::unload(int i) {
NotifyObservers(&ev) ;
}

bool SamplePool::loadSoundFont(const char *path) {
/*
Returns an element of
{SLOAD_OK, SLOAD_ERR_MAX_SOUNDFONTS, SLOAD_ERR_INPUT_FILE}.
*/
int SamplePool::loadSoundFont(const char *path) {

sfBankID id=SoundFontManager::GetInstance()->LoadBank(path) ;
if (id==-1) {
return false ;
}
sfBankID id = SoundFontManager::GetInstance()->LoadBank(path);
if (id==-SF_BANK_TABLE_FULL) {
return SLOAD_ERR_MAX_SOUNDFONTS ;
} else if (id < 0) {
return SLOAD_ERR_INPUT_FILE;
}

// Grab the sample offset
// Grab the sample offset

long offset=sfGetSMPLOffset(id) ;
long offset = sfGetSMPLOffset(id);

// Add all presets of the sf
// Add all presets of the sf

WORD presetCount=0 ;
SFPRESETHDRPTR pHeaders=sfGetPresetHdrs(id,&presetCount);
WORD presetCount = 0;
SFPRESETHDRPTR pHeaders=sfGetPresetHdrs(id,&presetCount);

for (int i=0;i<presetCount;i++) {
if (count_<MAX_PIG_SAMPLES) {
sfPresetHdr current=pHeaders[i] ;
wav_[count_]=new SoundFontPreset(id,i) ;
const char *name=pHeaders[i].achPresetName ;
names_[count_]=(char*)SYS_MALLOC(strlen(name)+1) ;
strcpy(names_[count_],name) ;
count_++ ;
Trace::Log("loadSoundFont", "%s", name);
names_[count_] = (char *)SYS_MALLOC(strlen(name) + 1);
strcpy(names_[count_], name);
count_++;
}
}
/*
// Get Sample information

WORD headerCount=0 ;
SFSAMPLEHDRPTR &headers=sfGetSampHdrs(id,&headerCount );

// Loop on every sample, add them

for (int i=0;i<headerCount;i++) {
if (count_<MAX_PIG_SAMPLES) {
sfSampleHdr &current=headers[i] ;
wav_[count_]=new SoundFontSample(current) ;
const char *name=headers[i].achSampleName ;
names_[count_]=(char*)SYS_MALLOC(strlen(name)+1) ;
strcpy(names_[count_],name) ;
count_++ ;
}
}
*/ return true ;
/*
// Get Sample information

WORD headerCount=0 ;
SFSAMPLEHDRPTR &headers=sfGetSampHdrs(id,&headerCount );

// Loop on every sample, add them

for (int i=0;i<headerCount;i++) {
if (count_<MAX_PIG_SAMPLES) {
sfSampleHdr &current=headers[i] ;
wav_[count_]=new SoundFontSample(current) ;
const char *name=headers[i].achSampleName ;
names_[count_]=(char*)SYS_MALLOC(strlen(name)+1) ;
strcpy(names_[count_],name) ;
count_++ ;
}
}
*/
return SLOAD_OK;
} ;
Loading