Browse Source

trying to find the default path in tars

master
Nils 3 years ago
parent
commit
28c9320ae5
  1. 2
      engine/api.py
  2. 4
      engine/auditioner.py
  3. 23
      engine/instrument.py
  4. 28
      engine/main.py
  5. 41
      extra/generate-round-robin.py
  6. 1024
      extra/test.sfz
  7. 4
      qtgui/instrument.py
  8. 2
      template/calfbox/sampler_layer.c
  9. 2
      template/calfbox/tarfile.h

2
engine/api.py

@ -148,7 +148,7 @@ def auditionerInstrument(idkey:tuple):
var = originalInstrument.currentVariant
else:
var = originalInstrument.defaultVariant
session.data.auditioner.loadInstrument(originalInstrument.tarFilePath, var)
session.data.auditioner.loadInstrument(originalInstrument.tarFilePath, originalInstrument.rootPrefixPath, var)
callbacks._auditionerInstrumentChanged(libraryId, instrumentId)
def getAvailableAuditionerPorts()->dict:

4
engine/auditioner.py

@ -92,7 +92,7 @@ class Auditioner(object):
return result
def loadInstrument(self, tarFilePath, variantSfzFileName:str):
def loadInstrument(self, tarFilePath, rootPrefixPath:str, variantSfzFileName:str):
"""load_patch_from_tar is blocking. This function will return when the instrument is ready
to play.
@ -103,7 +103,7 @@ class Auditioner(object):
#newProgramNumber = self.instrumentLayer.engine.get_unused_program()
programNumber = 1
name = variantSfzFileName
self.program = self.instrumentLayer.engine.load_patch_from_tar(programNumber, tarFilePath, variantSfzFileName, name)
self.program = self.instrumentLayer.engine.load_patch_from_tar(programNumber, tarFilePath, rootPrefixPath+variantSfzFileName, name)
self.instrumentLayer.engine.set_patch(1, programNumber) #1 is the channel, counting from 1. #TODO: we want this to be on all channels.
self.currentVariant = variantSfzFileName
logger.info(f"Finished loading samples for auditioner {variantSfzFileName}")

23
engine/instrument.py

@ -95,13 +95,21 @@ class Instrument(object):
self.cboxMidiPortUid = None
self.metadata = metadata #parsed from the ini file. See self.exportMetadata for the pythonic dict
self.instrumentsInLibraryCount = None #injected by the creating process. Counted live in the program, not included in the ini file.
self.tarFilePath = tarFilePath
self.name = metadata["name"]
self.midiInputPortName = metadata["name"]
self.midiInputPortName = f"[{libraryId}-{self.id}] " + metadata["name"]
self.variants = metadata["variants"].split(",")
self.defaultVariant = metadata["defaultVariant"]
self.enabled = False #means loaded.
if "root" in metadata:
if metadata["root"].endswith("/"):
self.rootPrefixPath = metadata["root"]
else:
self.rootPrefixPath = metadata["root"] + "/"
else:
self.rootPrefixPath = ""
#Calfbox. The JACK ports are constructed without samples at first.
self.scene = cbox.Document.get_engine().new_scene()
@ -138,6 +146,7 @@ class Instrument(object):
#We could call self.load() now, but we delay that for the user experience. See docstring.
def exportStatus(self):
"""The call-often function to get the instrument status. Includes only data that can
actually change during runtime."""
@ -174,6 +183,7 @@ class Instrument(object):
result["defaultVariant"] = self.metadata["defaultVariant"] #str
result["defaultVariantWithoutSfzExtension"] = self.metadata["defaultVariant"].rstrip(".sfz") #str
result["tags"] = self.metadata["tags"].split(",") # list of str
result["instrumentsInLibraryCount"] = self.instrumentsInLibraryCount # int
#Optional Tags.
@ -224,11 +234,20 @@ class Instrument(object):
#help (self.allInstrumentLayers[self.defaultPortUid].engine) #shows the functions to load programs into channels etc.
#newProgramNumber = self.instrumentLayer.engine.get_unused_program()
programNumber = self.metadata["variants"].index(variantSfzFileName) #counts from 1
self.program = self.instrumentLayer.engine.load_patch_from_tar(programNumber, self.tarFilePath, variantSfzFileName, self.metadata["name"])
self.program = self.instrumentLayer.engine.load_patch_from_tar(programNumber, self.tarFilePath, self.rootPrefixPath+variantSfzFileName, self.metadata["name"]) #tar_name, sfz_name, display_name
self.instrumentLayer.engine.set_patch(1, programNumber) #1 is the channel, counting from 1. #TODO: we want this to be on all channels.
#self.program is always None ?
#self.instrumentLayer is type DocInstrument
#self.instrumentLayer.engine is type SamplerEngine
#self.instrumentLayer.engine.get_patches returns a dict like {0: ('Harpsichord.sfz', <calfbox.cbox.SamplerProgram object at 0x7fd324226a60>, 16)}
#Only ever index 0 is used because we have one patch per port
#self.instrumentLayer.engine.get_patches()[0][1] is the cbox.SamplerProgram. That should have been self.program, but isn't!
self.program = self.instrumentLayer.engine.get_patches()[0][1]
print (self.program.status())
self.currentVariant = variantSfzFileName
logger.info(f"Finished loading samples for instrument {variantSfzFileName} with id key {self.idKey}")
def enable(self):
self.enabled = True

28
engine/main.py

@ -22,7 +22,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging; logger = logging.getLogger(__name__); logger.info("import")
#Python Standard Lib
import os.path
import configparser
import pathlib
import tarfile
@ -77,9 +76,12 @@ class Data(TemplateData):
#Parse all tar libraries and load them all. ALL OF THEM!
#for each library in ...
self.libraries = {} # libraryId:int : Library-object
lib = Library(parentData=self, tarFilePath="/home/nils/lss/test-data.tar")
self.libraries[lib.id] = lib
basePath = pathlib.Path("/home/nils/samples/Tembro/out/")
for f in basePath.glob('*.tar'):
if f.is_file() and f.suffix == ".tar":
lib = Library(parentData=self, tarFilePath=f)
self.libraries[lib.id] = lib
def exportMetadata(self)->dict:
"""Data we sent in callbacks. This is the initial 'build-the-instrument-database' function.
@ -100,14 +102,22 @@ class Library(object):
You get all metadata from this.
The samples are not loaded when Library() returns. The API can loop over Instrument.allInstruments
and call instr.loadSamples() and send a feedback to callbacks.
There is also a shortcut. First only an external .ini is loaded, which is much faster than
unpacking the tar. If no additional data like images are needed (which is always the case
at this version 1.0) we parse this external ini directly to build our database.
"""
def __init__(self, parentData, tarFilePath):#
self.parentData = parentData
self.tarFilePath = pathlib.Path(tarFilePath)
if not tarFilePath.endswith(".tar"):
self.tarFilePath = tarFilePath #pathlib.Path()
if not tarFilePath.suffix == ".tar":
raise RuntimeError(f"Wrong file {tarFilePath}")
needTarData = False #TODO: If we have images etc. in the future.
if needTarData:
with tarfile.open(name=tarFilePath, mode='r:') as opentarfile:
iniFileObject = TextIOWrapper(opentarfile.extractfile("library.ini"))
self.config = configparser.ConfigParser()
@ -121,18 +131,22 @@ class Library(object):
except KeyError: #file not found
imageAsBytes = None
"""
else: #the default case for now.
iniName = str(tarFilePath)[:-4] + ".ini"
self.config = configparser.ConfigParser()
self.config.read(iniName)
self.id = self.config["library"]["id"]
instrumentSections = self.config.sections()
instrumentSections.remove("library")
instrumentsInLibraryCount = len(instrumentSections)
self.instruments = {} # instrId : Instrument()
for iniSection in instrumentSections:
instrObj = Instrument(self, self.config["library"]["id"], self.config[iniSection], tarFilePath)
instrObj.instrumentsInLibraryCount = instrumentsInLibraryCount
self.instruments[self.config[iniSection]["id"]] = instrObj
#At a later point Instrument.loadSamples() must be called. This is done in the API.
def exportMetadata(self)->dict:
"""Return a dictionary with each key is an instrument id, but also a special key "library"
with our own metadata. Allows the callbacks receiver to construct a hierarchy"""

41
extra/generate-round-robin.py

@ -0,0 +1,41 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
This application is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
"""
Outputs to standard output
Uses midi note keys as sample file names.
"""
groupstring = """
<group>
seq_length=3
key={}
<region>seq_position=1 sample={}.wav transpose=0
<region>seq_position=2 sample={}.wav transpose=-1
<region>seq_position=3 sample={}.wav transpose=-2
"""
for keynum in range(127+1):
print (groupstring.format(keynum, keynum, keynum+1, keynum+2))

1024
extra/test.sfz

File diff suppressed because it is too large

4
qtgui/instrument.py

@ -309,7 +309,9 @@ class GuiInstrument(QtWidgets.QTreeWidgetItem):
elif key == "id-key": #tuple
libId, instrId = instrumentDict[key]
self.setText(index, f"{libId}-{instrId}")
#self.setText(index, f"{libId}-{str(instrId).zfill(3)}")
zeros = int(instrumentDict["instrumentsInLibraryCount"]/10)+1
self.setText(index, str(instrId).zfill(zeros))
"""
elif key == "state": #use parameter for initial value. loaded from file or default = False.

2
template/calfbox/sampler_layer.c

@ -1319,7 +1319,7 @@ void sampler_layer_data_finalize(struct sampler_layer_data *l, struct sampler_la
l->computed.eff_waveform = cbox_wavebank_get_waveform(p->name, p->tarfile, p->sample_dir, l->sample, &error);
if (!l->computed.eff_waveform)
{
g_warning("Cannot load waveform %s: %s", l->sample, error ? error->message : "unknown error");
g_warning("Cannot load waveform \"%s\" in sample_dir \"%s\" : \"%s\"", l->sample, p->sample_dir, error ? error->message : "unknown error");
g_error_free(error);
}
}

2
template/calfbox/tarfile.h

@ -38,7 +38,7 @@ struct cbox_tarfile
int refs;
GHashTable *items_byname;
GHashTable *items_byname_nc;
char *file_pathname;
char *file_pathname; //full path to the .tar file with filename.ext
};
struct cbox_tarpool

Loading…
Cancel
Save