1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 25 апр. 2019 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <dsp/dsp.h> 23 24 #include <core/files/Model3DFile.h> 25 26 #include <plugins/room_builder.h> 27 #include <dsp/endian.h> 28 #include <core/fade.h> 29 #include <core/stdlib/math.h> 30 #include <core/files/lspc/LSPCAudioWriter.h> 31 #include <core/files/AudioFile.h> 32 33 #define TMP_BUF_SIZE 4096 34 #define CONV_RANK 10 35 #define TRACE_PORT(p) lsp_trace(" port id=%s", (p)->metadata()->id); 36 37 namespace lsp 38 { 39 static const float band_freqs[] = 40 { 41 73.0f, 42 156.0f, 43 332.0f, 44 707.0f, 45 1507.0f, 46 3213.0f, 47 6849.0f 48 }; 49 50 //------------------------------------------------------------------------- 51 // 3D Scene loader ~SceneLoader()52 room_builder_base::SceneLoader::~SceneLoader() 53 { 54 } 55 56 init(room_builder_base * base)57 void room_builder_base::SceneLoader::init(room_builder_base *base) 58 { 59 pCore = base; 60 sScene.clear(); 61 } 62 destroy()63 void room_builder_base::SceneLoader::destroy() 64 { 65 sScene.destroy(); 66 } 67 run()68 status_t room_builder_base::RenderLauncher::run() 69 { 70 return pBuilder->start_rendering(); 71 } 72 73 template <class T> kvt_deploy(KVTStorage * s,const char * base,const char * branch,T value,size_t flags)74 static bool kvt_deploy(KVTStorage *s, const char *base, const char *branch, T value, size_t flags) 75 { 76 char name[0x100]; // Should be enough 77 size_t len = ::strlen(base) + ::strlen(branch) + 2; 78 if (len >= 0x100) 79 return false; 80 81 char *tail = ::stpcpy(name, base); 82 *(tail++) = '/'; 83 stpcpy(tail, branch); 84 85 return s->put(name, value, flags) == STATUS_OK; 86 } 87 run()88 status_t room_builder_base::SceneLoader::run() 89 { 90 // Clear scene 91 sScene.clear(); 92 93 // Check state 94 size_t nobjs = 0; 95 status_t res = STATUS_UNSPECIFIED; 96 97 // Load the scene file 98 if (pCore->p3DFile == NULL) 99 res = STATUS_UNKNOWN_ERR; 100 else if (::strlen(sPath) > 0) 101 { 102 res = Model3DFile::load(&sScene, sPath, true); 103 if (res == STATUS_OK) 104 { 105 // Initialize object properties 106 nobjs = sScene.num_objects(); 107 } 108 } 109 110 // Get KVT storage and deploy new values 111 KVTStorage *kvt = pCore->kvt_lock(); 112 if (kvt == NULL) 113 return STATUS_UNKNOWN_ERR; 114 115 // Now initialize object properties 116 lsp_trace("Extra loading flags=0x%x", int(nFlags)); 117 size_t f_extra = (nFlags & (PF_STATE_IMPORT | PF_PRESET_IMPORT | PF_STATE_RESTORE)) ? KVT_KEEP | KVT_TX : KVT_TX; 118 size_t f_hue = (nFlags & (PF_STATE_IMPORT | PF_STATE_RESTORE)) ? KVT_KEEP | KVT_TX : KVT_TX; 119 120 char base[128]; 121 kvt_deploy(kvt, "/scene", "objects", int32_t(nobjs), KVT_TX); 122 kvt_deploy(kvt, "/scene", "selected", 0.0f, f_extra); 123 124 for (size_t i=0; i<nobjs; ++i) 125 { 126 Object3D *obj = sScene.object(i); 127 if (obj == NULL) 128 return STATUS_UNKNOWN_ERR; 129 const point3d_t *c = obj->center(); 130 131 sprintf(base, "/scene/object/%d", int(i)); 132 lsp_trace("Deploying KVT parameters for %s", base); 133 134 kvt_deploy(kvt, base, "name", obj->get_name(), KVT_TX); // Always overwrite name 135 136 kvt_deploy(kvt, base, "enabled", 1.0f, f_extra); 137 kvt_deploy(kvt, base, "center/x", c->x, KVT_TX | KVT_TRANSIENT); // Always overwrite, do not save in state 138 kvt_deploy(kvt, base, "center/y", c->y, KVT_TX | KVT_TRANSIENT); // Always overwrite, do not save in state 139 kvt_deploy(kvt, base, "center/z", c->z, KVT_TX | KVT_TRANSIENT); // Always overwrite, do not save in state 140 kvt_deploy(kvt, base, "position/x", 0.0f, f_extra); 141 kvt_deploy(kvt, base, "position/y", 0.0f, f_extra); 142 kvt_deploy(kvt, base, "position/z", 0.0f, f_extra); 143 kvt_deploy(kvt, base, "rotation/yaw", 0.0f, f_extra); 144 kvt_deploy(kvt, base, "rotation/pitch", 0.0f, f_extra); 145 kvt_deploy(kvt, base, "rotation/roll", 0.0f, f_extra); 146 kvt_deploy(kvt, base, "scale/x", 100.0f, f_extra); 147 kvt_deploy(kvt, base, "scale/y", 100.0f, f_extra); 148 kvt_deploy(kvt, base, "scale/z", 100.0f, f_extra); 149 kvt_deploy(kvt, base, "color/hue", float(i) / float(nobjs), f_hue); // Always overwrite hue 150 151 kvt_deploy(kvt, base, "material/absorption/outer", 1.5f, f_extra); // Absorption of concrete material 152 kvt_deploy(kvt, base, "material/dispersion/outer", 1.0f, f_extra); 153 kvt_deploy(kvt, base, "material/diffusion/outer", 1.0f, f_extra); 154 kvt_deploy(kvt, base, "material/transparency/outer", 48.0f, f_extra); 155 156 kvt_deploy(kvt, base, "material/absorption/inner", 1.5f, f_extra); 157 kvt_deploy(kvt, base, "material/dispersion/inner", 1.0f, f_extra); 158 kvt_deploy(kvt, base, "material/diffusion/inner", 1.0f, f_extra); 159 kvt_deploy(kvt, base, "material/transparency/inner", 52.0f, f_extra); 160 161 kvt_deploy(kvt, base, "material/absorption/link", 1.0f, f_extra); 162 kvt_deploy(kvt, base, "material/dispersion/link", 1.0f, f_extra); 163 kvt_deploy(kvt, base, "material/diffusion/link", 1.0f, f_extra); 164 kvt_deploy(kvt, base, "material/transparency/link", 1.0f, f_extra); 165 166 kvt_deploy(kvt, base, "material/sound_speed", 4250.0f, f_extra); // Sound speed in concrete material 167 } 168 169 // Drop rare (unused) objects 170 kvt_cleanup_objects(kvt, nobjs); 171 172 pCore->kvt_release(); 173 174 return res; 175 } 176 kvt_cleanup_objects(KVTStorage * kvt,size_t objects)177 void room_builder_base::kvt_cleanup_objects(KVTStorage *kvt, size_t objects) 178 { 179 KVTIterator *it = kvt->enum_branch("/scene/object"); 180 while (it->next() == STATUS_OK) 181 { 182 const char *id = it->id(); 183 if (id == NULL) 184 continue; 185 186 // Must be a pure object identifier 187 errno = 0; 188 char *endptr; 189 long value = ::strtol(id, &endptr, 10); 190 if ((errno != 0) || (size_t(endptr - id) != size_t(::strlen(id)))) 191 continue; 192 193 // Remove the object 194 if ((value < 0) || (value >= ssize_t(objects))) 195 { 196 lsp_trace("Removing KVT parameters from %s", it->name()); 197 it->remove_branch(); 198 } 199 } 200 } 201 202 template <class T> kvt_fetch(KVTStorage * s,const char * base,const char * branch,T * value,T dfl)203 static bool kvt_fetch(KVTStorage *s, const char *base, const char *branch, T *value, T dfl) 204 { 205 char name[0x100]; // Should be enough; 206 size_t len = ::strlen(base) + ::strlen(branch) + 2; 207 if (len >= 0x100) 208 return false; 209 210 char *tail = ::stpcpy(name, base); 211 *(tail++) = '/'; 212 stpcpy(tail, branch); 213 214 return s->get_dfl(name, value, dfl); 215 } 216 read_object_properties(obj_props_t * props,const char * base,KVTStorage * kvt)217 void room_builder_base::read_object_properties(obj_props_t *props, const char *base, KVTStorage *kvt) 218 { 219 float enabled; 220 221 kvt_fetch(kvt, base, "name", &props->sName, "unnamed"); 222 kvt_fetch(kvt, base, "enabled", &enabled, 1.0f); 223 kvt_fetch(kvt, base, "center/x", &props->sCenter.x, 0.0f); 224 kvt_fetch(kvt, base, "center/y", &props->sCenter.y, 0.0f); 225 kvt_fetch(kvt, base, "center/z", &props->sCenter.z, 0.0f); 226 kvt_fetch(kvt, base, "position/x", &props->sMove.dx, 0.0f); 227 kvt_fetch(kvt, base, "position/y", &props->sMove.dy, 0.0f); 228 kvt_fetch(kvt, base, "position/z", &props->sMove.dz, 0.0f); 229 kvt_fetch(kvt, base, "rotation/yaw", &props->fYaw, 0.0f); 230 kvt_fetch(kvt, base, "rotation/pitch", &props->fPitch, 0.0f); 231 kvt_fetch(kvt, base, "rotation/roll", &props->fRoll, 0.0f); 232 kvt_fetch(kvt, base, "scale/x", &props->sScale.dx, 1.0f); 233 kvt_fetch(kvt, base, "scale/y", &props->sScale.dy, 1.0f); 234 kvt_fetch(kvt, base, "scale/z", &props->sScale.dz, 1.0f); 235 kvt_fetch(kvt, base, "color/hue", &props->fHue, 0.0f); 236 237 kvt_fetch(kvt, base, "material/absorption/outer", &props->fAbsorption[0], 1.5f); 238 kvt_fetch(kvt, base, "material/dispersion/outer", &props->fDispersion[0], 1.0f); 239 kvt_fetch(kvt, base, "material/dissipation/outer", &props->fDiffusion[0], 1.0f); 240 kvt_fetch(kvt, base, "material/transparency/outer", &props->fTransparency[0], 48.0f); 241 242 kvt_fetch(kvt, base, "material/absorption/inner", &props->fAbsorption[1], 1.5f); 243 kvt_fetch(kvt, base, "material/dispersion/inner", &props->fDispersion[1], 1.0f); 244 kvt_fetch(kvt, base, "material/diffusion/inner", &props->fDiffusion[1], 1.0f); 245 kvt_fetch(kvt, base, "material/transparency/inner", &props->fTransparency[1], 52.0f); 246 247 kvt_fetch(kvt, base, "material/absorption/link", &props->lnkAbsorption, 1.0f); 248 kvt_fetch(kvt, base, "material/dispersion/link", &props->lnkDispersion, 1.0f); 249 kvt_fetch(kvt, base, "material/diffusion/link", &props->lnkDiffusion, 1.0f); 250 kvt_fetch(kvt, base, "material/transparency/link", &props->lnkTransparency, 1.0f); 251 252 kvt_fetch(kvt, base, "material/sound_speed", &props->fSndSpeed, 4250.0f); 253 254 props->bEnabled = (enabled >= 0.5f); 255 } 256 build_object_matrix(matrix3d_t * m,const obj_props_t * props,const matrix3d_t * world)257 void room_builder_base::build_object_matrix(matrix3d_t *m, const obj_props_t *props, const matrix3d_t *world) 258 { 259 matrix3d_t tmp; 260 261 // Copy world matrix 262 *m = *world; 263 264 // Apply translation 265 dsp::init_matrix3d_translate(&tmp, 266 props->sCenter.x + props->sMove.dx, 267 props->sCenter.y + props->sMove.dy, 268 props->sCenter.z + props->sMove.dz 269 ); 270 dsp::apply_matrix3d_mm1(m, &tmp); 271 272 // Apply rotation 273 dsp::init_matrix3d_rotate_z(&tmp, props->fYaw * M_PI / 180.0f); 274 dsp::apply_matrix3d_mm1(m, &tmp); 275 276 dsp::init_matrix3d_rotate_y(&tmp, props->fPitch * M_PI / 180.0f); 277 dsp::apply_matrix3d_mm1(m, &tmp); 278 279 dsp::init_matrix3d_rotate_x(&tmp, props->fRoll * M_PI / 180.0f); 280 dsp::apply_matrix3d_mm1(m, &tmp); 281 282 // Apply scale 283 dsp::init_matrix3d_scale(&tmp, props->sScale.dx * 0.01f, props->sScale.dy * 0.01f, props->sScale.dz * 0.01f); 284 dsp::apply_matrix3d_mm1(m, &tmp); 285 286 // Move center to (0, 0, 0) point 287 dsp::init_matrix3d_translate(&tmp, -props->sCenter.x, -props->sCenter.y, -props->sCenter.z); 288 dsp::apply_matrix3d_mm1(m, &tmp); 289 } 290 run()291 status_t room_builder_base::Renderer::run() 292 { 293 // Perform processing 294 lsp_trace("Launching process() method"); 295 pBuilder->enRenderStatus = STATUS_IN_PROCESS; 296 status_t res = pRT->process(nThreads, 1.0f); 297 298 // Deploy success result 299 if (res == STATUS_OK) 300 res = pBuilder->commit_samples(vSamples); 301 302 // Free all resources 303 if (lkTerminate.lock()) 304 { 305 pRT->destroy(true); 306 delete pRT; 307 pRT = NULL; 308 lkTerminate.unlock(); 309 } 310 311 room_builder_base::destroy_samples(vSamples); 312 313 return pBuilder->enRenderStatus = res; 314 } 315 terminate()316 void room_builder_base::Renderer::terminate() 317 { 318 if (lkTerminate.lock()) 319 { 320 if (pRT != NULL) 321 pRT->cancel(); 322 lkTerminate.unlock(); 323 } 324 } 325 run()326 status_t room_builder_base::Configurator::run() 327 { 328 return pBuilder->reconfigure(&sConfig); 329 } 330 bind(size_t sample_id,capture_t * capture)331 void room_builder_base::SampleSaver::bind(size_t sample_id, capture_t *capture) 332 { 333 nSampleID = sample_id; 334 IPort *p = capture->pOutFile; 335 if (p == NULL) 336 return; 337 path_t *path = p->getBuffer<path_t>(); 338 if (path == NULL) 339 return; 340 const char *spath = path->get_path(); 341 if (spath != NULL) 342 { 343 ::strncpy(sPath, spath, PATH_MAX); 344 sPath[PATH_MAX] = '\0'; 345 } 346 else 347 sPath[0] = '\0'; 348 } 349 run()350 status_t room_builder_base::SampleSaver::run() 351 { 352 return pBuilder->save_sample(sPath, nSampleID); 353 } 354 355 //------------------------------------------------------------------------- room_builder_base(const plugin_metadata_t & metadata,size_t inputs)356 room_builder_base::room_builder_base(const plugin_metadata_t &metadata, size_t inputs): 357 plugin_t(metadata), 358 s3DLauncher(this), 359 sConfigurator(this), 360 sSaver(this) 361 { 362 nInputs = inputs; 363 nReconfigReq = 0; 364 nReconfigResp = 0; 365 366 nRenderThreads = 0; 367 fRenderQuality = 0.5f; 368 bRenderNormalize= true; 369 enRenderStatus = STATUS_OK; 370 fRenderProgress = 0.0f; 371 fRenderCmd = 0.0f; 372 nFftRank = 0; 373 374 nSceneStatus = STATUS_UNSPECIFIED; 375 fSceneProgress = 0.0f; 376 nSync = 0; 377 378 pBypass = NULL; 379 pRank = NULL; 380 pDry = NULL; 381 pWet = NULL; 382 pRenderThreads = NULL; 383 pRenderQuality = NULL; 384 pRenderStatus = NULL; 385 pRenderProgress = NULL; 386 pRenderNormalize= NULL; 387 pRenderCmd = NULL; 388 pOutGain = NULL; 389 pPredelay = NULL; 390 p3DFile = NULL; 391 p3DProgress = NULL; 392 p3DStatus = NULL; 393 p3DOrientation = NULL; 394 pScaleX = NULL; 395 pScaleY = NULL; 396 pScaleZ = NULL; 397 pRenderer = NULL; 398 399 pData = NULL; 400 pExecutor = NULL; 401 402 dsp::init_vector_dxyz(&sScale, 1.0f, 1.0f, 1.0f); 403 } 404 ~room_builder_base()405 room_builder_base::~room_builder_base() 406 { 407 } 408 init(IWrapper * wrapper)409 void room_builder_base::init(IWrapper *wrapper) 410 { 411 // Pass wrapper 412 plugin_t::init(wrapper); 413 414 // Remember executor service 415 pExecutor = wrapper->get_executor(); 416 lsp_trace("Executor = %p", pExecutor); 417 418 // Allocate memory 419 size_t tmp_buf_size = TMP_BUF_SIZE * sizeof(float); 420 size_t thumb_size = room_builder_base_metadata::MESH_SIZE * 421 room_builder_base_metadata::TRACKS_MAX * sizeof(float); 422 size_t alloc = tmp_buf_size * (room_builder_base_metadata::CONVOLVERS + 2) + 423 thumb_size * room_builder_base_metadata::CAPTURES; 424 uint8_t *ptr = alloc_aligned<uint8_t>(pData, alloc); 425 if (pData == NULL) 426 return; 427 428 // Initialize 3D loader 429 s3DLoader.init(this); 430 431 // Initialize inputs 432 for (size_t i=0; i<2; ++i) 433 { 434 input_t *in = &vInputs[i]; 435 in->vIn = NULL; 436 in->pIn = NULL; 437 in->pPan = NULL; 438 } 439 440 // Initialize output channels 441 for (size_t i=0; i<2; ++i) 442 { 443 channel_t *c = &vChannels[i]; 444 445 if (!c->sPlayer.init(room_builder_base_metadata::CAPTURES, 32)) 446 return; 447 if (!c->sEqualizer.init(room_builder_base_metadata::EQ_BANDS + 2, CONV_RANK)) 448 return; 449 c->sEqualizer.set_mode(EQM_BYPASS); 450 451 c->fDryPan[0] = 0.0f; 452 c->fDryPan[1] = 0.0f; 453 454 c->vOut = NULL; 455 c->vBuffer = reinterpret_cast<float *>(ptr); 456 ptr += tmp_buf_size; 457 458 c->pOut = NULL; 459 460 c->pWetEq = NULL; 461 c->pLowCut = NULL; 462 c->pLowFreq = NULL; 463 c->pHighCut = NULL; 464 c->pHighFreq = NULL; 465 466 for (size_t j=0; j<room_builder_base_metadata::EQ_BANDS; ++j) 467 c->pFreqGain[j] = NULL; 468 } 469 470 // Initialize sources 471 for (size_t i=0; i<room_builder_base_metadata::SOURCES; ++i) 472 { 473 source_t *src = &vSources[i]; 474 475 src->bEnabled = false; 476 src->enType = RT_AS_TRIANGLE; 477 dsp::init_point_xyz(&src->sPos, 0.0f, -1.0f, 0.0f); 478 src->fYaw = 0.0f; 479 src->fPitch = 0.0f; 480 src->fRoll = 0.0f; 481 src->fSize = 0.0f; 482 src->fHeight = 0.0f; 483 src->fAngle = 0.0f; 484 src->fCurvature = 1.0f; 485 src->fAmplitude = 1.0f; 486 487 src->pEnabled = NULL; 488 src->pType = NULL; 489 src->pPhase = NULL; 490 src->pPosX = NULL; 491 src->pPosY = NULL; 492 src->pPosZ = NULL; 493 src->pYaw = NULL; 494 src->pPitch = NULL; 495 src->pRoll = NULL; 496 src->pSize = NULL; 497 src->pHeight = NULL; 498 src->pAngle = NULL; 499 src->pCurvature = NULL; 500 } 501 502 // Initialize captures 503 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 504 { 505 capture_t *cap = &vCaptures[i]; 506 507 dsp::init_point_xyz(&cap->sPos, 0.0f, 1.0f, 0.0f); 508 cap->fYaw = 0.0f; 509 cap->fPitch = 0.0f; 510 cap->fRoll = 0.0f; 511 cap->fCapsule = room_builder_base_metadata::CAPSULE_DFL; 512 cap->sConfig = RT_CC_XY; 513 cap->fAngle = room_builder_base_metadata::ANGLE_DFL; 514 cap->fDistance = room_builder_base_metadata::DISTANCE_DFL; 515 cap->enDirection = RT_AC_OMNI; 516 cap->enSide = RT_AC_BIDIR; 517 518 cap->bEnabled = (i == 0); 519 cap->nRMin = 1; 520 cap->nRMax = -1; 521 522 cap->fHeadCut = 0.0f; 523 cap->fTailCut = 0.0f; 524 cap->fFadeIn = 0.0f; 525 cap->fFadeOut = 0.0f; 526 cap->bReverse = false; 527 cap->fMakeup = 1.0f; 528 cap->nLength = 0; 529 cap->nStatus = STATUS_NO_DATA; 530 cap->fCurrLen = 0.0f; 531 cap->fMaxLen = 0.0f; 532 533 cap->nChangeReq = 0; 534 cap->nChangeResp = 0; 535 cap->bCommit = false; 536 cap->bSync = false; 537 cap->bExport = false; 538 539 cap->pCurr = NULL; 540 cap->pSwap = NULL; 541 542 for (size_t j=0; j<room_builder_base_metadata::TRACKS_MAX; ++j) 543 { 544 cap->vThumbs[j] = reinterpret_cast<float *>(ptr); 545 ptr += room_builder_base_metadata::MESH_SIZE * sizeof(float); 546 } 547 548 cap->pEnabled = NULL; 549 cap->pRMin = NULL; 550 cap->pRMax = NULL; 551 cap->pPosX = NULL; 552 cap->pPosY = NULL; 553 cap->pPosZ = NULL; 554 cap->pYaw = NULL; 555 cap->pPitch = NULL; 556 cap->pRoll = NULL; 557 cap->pCapsule = NULL; 558 cap->pConfig = NULL; 559 cap->pAngle = NULL; 560 cap->pDistance = NULL; 561 cap->pDirection = NULL; 562 cap->pSide = NULL; 563 564 cap->pHeadCut = NULL; 565 cap->pTailCut = NULL; 566 cap->pFadeIn = NULL; 567 cap->pFadeOut = NULL; 568 cap->pListen = NULL; 569 cap->pReverse = NULL; 570 cap->pMakeup = NULL; 571 cap->pStatus = NULL; 572 cap->pLength = NULL; 573 cap->pCurrLen = NULL; 574 cap->pMaxLen = NULL; 575 cap->pThumbs = NULL; 576 577 cap->pOutFile = NULL; 578 cap->pSaveCmd = NULL; 579 cap->pSaveStatus = NULL; 580 cap->pSaveProgress = NULL; 581 } 582 583 // Initialize convolvers 584 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 585 { 586 lsp_trace("Binding convolution #%d ports", int(i)); 587 convolver_t *c = &vConvolvers[i]; 588 589 c->pCurr = NULL; 590 c->pSwap = NULL; 591 592 c->nSampleID = 0; 593 c->nTrackID = 0; 594 595 c->vBuffer = reinterpret_cast<float *>(ptr); 596 ptr += tmp_buf_size; 597 598 c->fPanIn[0] = 0.0f; 599 c->fPanIn[1] = 0.0f; 600 c->fPanOut[0] = 0.0f; 601 c->fPanOut[1] = 0.0f; 602 603 c->pMakeup = NULL; 604 c->pPanIn = NULL; 605 c->pPanOut = NULL; 606 c->pSample = NULL; 607 c->pTrack = NULL; 608 c->pPredelay = NULL; 609 c->pMute = NULL; 610 c->pActivity = NULL; 611 } 612 613 // Bind ports 614 size_t port_id = 0; 615 616 lsp_trace("Binding audio ports"); 617 for (size_t i=0; i<nInputs; ++i) 618 { 619 TRACE_PORT(vPorts[port_id]); 620 vInputs[i].pIn = vPorts[port_id++]; 621 } 622 for (size_t i=0; i<2; ++i) 623 { 624 TRACE_PORT(vPorts[port_id]); 625 vChannels[i].pOut = vPorts[port_id++]; 626 } 627 628 // Bind controlling ports 629 lsp_trace("Binding common ports"); 630 TRACE_PORT(vPorts[port_id]); 631 pBypass = vPorts[port_id++]; 632 TRACE_PORT(vPorts[port_id]); // Skip view selector 633 port_id++; 634 TRACE_PORT(vPorts[port_id]); // Skip editor selector 635 port_id++; 636 TRACE_PORT(vPorts[port_id]); // Skip processor selector 637 port_id++; 638 TRACE_PORT(vPorts[port_id]); // FFT rank 639 pRank = vPorts[port_id++]; 640 TRACE_PORT(vPorts[port_id]); // Pre-delay 641 pPredelay = vPorts[port_id++]; 642 643 for (size_t i=0; i<nInputs; ++i) // Panning ports 644 { 645 TRACE_PORT(vPorts[port_id]); 646 vInputs[i].pPan = vPorts[port_id++]; 647 } 648 649 TRACE_PORT(vPorts[port_id]); 650 pDry = vPorts[port_id++]; 651 TRACE_PORT(vPorts[port_id]); 652 pWet = vPorts[port_id++]; 653 TRACE_PORT(vPorts[port_id]); 654 pOutGain = vPorts[port_id++]; 655 656 TRACE_PORT(vPorts[port_id]); 657 pRenderThreads = vPorts[port_id++]; 658 TRACE_PORT(vPorts[port_id]); 659 pRenderQuality = vPorts[port_id++]; 660 TRACE_PORT(vPorts[port_id]); 661 pRenderStatus = vPorts[port_id++]; 662 TRACE_PORT(vPorts[port_id]); 663 pRenderProgress = vPorts[port_id++]; 664 TRACE_PORT(vPorts[port_id]); 665 pRenderNormalize= vPorts[port_id++]; 666 TRACE_PORT(vPorts[port_id]); 667 pRenderCmd = vPorts[port_id++]; 668 669 TRACE_PORT(vPorts[port_id]); 670 p3DFile = vPorts[port_id++]; 671 TRACE_PORT(vPorts[port_id]); 672 p3DStatus = vPorts[port_id++]; 673 TRACE_PORT(vPorts[port_id]); 674 p3DProgress = vPorts[port_id++]; 675 TRACE_PORT(vPorts[port_id]); 676 p3DOrientation = vPorts[port_id++]; 677 TRACE_PORT(vPorts[port_id]); 678 pScaleX = vPorts[port_id++]; 679 TRACE_PORT(vPorts[port_id]); 680 pScaleY = vPorts[port_id++]; 681 TRACE_PORT(vPorts[port_id]); 682 pScaleZ = vPorts[port_id++]; 683 684 // Skip camera settings 685 TRACE_PORT(vPorts[port_id]); // Skip camera x 686 port_id++; 687 TRACE_PORT(vPorts[port_id]); // Skip camera y 688 port_id++; 689 TRACE_PORT(vPorts[port_id]); // Skip camera z 690 port_id++; 691 TRACE_PORT(vPorts[port_id]); // Skip camera yaw 692 port_id++; 693 TRACE_PORT(vPorts[port_id]); // Skip camera pitch 694 port_id++; 695 696 // Bind sources 697 TRACE_PORT(vPorts[port_id]); // Skip source selector 698 port_id++; 699 700 for (size_t i=0; i<room_builder_base_metadata::SOURCES; ++i) 701 { 702 source_t *src = &vSources[i]; 703 704 TRACE_PORT(vPorts[port_id]); 705 src->pEnabled = vPorts[port_id++]; 706 TRACE_PORT(vPorts[port_id]); 707 src->pType = vPorts[port_id++]; 708 TRACE_PORT(vPorts[port_id]); 709 src->pPhase = vPorts[port_id++]; 710 TRACE_PORT(vPorts[port_id]); 711 src->pPosX = vPorts[port_id++]; 712 TRACE_PORT(vPorts[port_id]); 713 src->pPosY = vPorts[port_id++]; 714 TRACE_PORT(vPorts[port_id]); 715 src->pPosZ = vPorts[port_id++]; 716 TRACE_PORT(vPorts[port_id]); 717 src->pYaw = vPorts[port_id++]; 718 TRACE_PORT(vPorts[port_id]); 719 src->pPitch = vPorts[port_id++]; 720 TRACE_PORT(vPorts[port_id]); 721 src->pRoll = vPorts[port_id++]; 722 TRACE_PORT(vPorts[port_id]); 723 src->pSize = vPorts[port_id++]; 724 TRACE_PORT(vPorts[port_id]); 725 src->pHeight = vPorts[port_id++]; 726 TRACE_PORT(vPorts[port_id]); 727 src->pAngle = vPorts[port_id++]; 728 TRACE_PORT(vPorts[port_id]); 729 src->pCurvature = vPorts[port_id++]; 730 731 TRACE_PORT(vPorts[port_id]); 732 port_id++; // Skip hue value 733 } 734 735 // Bind captures 736 TRACE_PORT(vPorts[port_id]); // Skip capture selector 737 port_id++; 738 739 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 740 { 741 capture_t *cap = &vCaptures[i]; 742 743 TRACE_PORT(vPorts[port_id]); 744 cap->pEnabled = vPorts[port_id++]; 745 TRACE_PORT(vPorts[port_id]); 746 cap->pRMin = vPorts[port_id++]; 747 TRACE_PORT(vPorts[port_id]); 748 cap->pRMax = vPorts[port_id++]; 749 TRACE_PORT(vPorts[port_id]); 750 cap->pPosX = vPorts[port_id++]; 751 TRACE_PORT(vPorts[port_id]); 752 cap->pPosY = vPorts[port_id++]; 753 TRACE_PORT(vPorts[port_id]); 754 cap->pPosZ = vPorts[port_id++]; 755 TRACE_PORT(vPorts[port_id]); 756 cap->pYaw = vPorts[port_id++]; 757 TRACE_PORT(vPorts[port_id]); 758 cap->pPitch = vPorts[port_id++]; 759 TRACE_PORT(vPorts[port_id]); 760 cap->pRoll = vPorts[port_id++]; 761 TRACE_PORT(vPorts[port_id]); 762 cap->pCapsule = vPorts[port_id++]; 763 TRACE_PORT(vPorts[port_id]); 764 cap->pConfig = vPorts[port_id++]; 765 TRACE_PORT(vPorts[port_id]); 766 cap->pAngle = vPorts[port_id++]; 767 TRACE_PORT(vPorts[port_id]); 768 cap->pDistance = vPorts[port_id++]; 769 TRACE_PORT(vPorts[port_id]); 770 cap->pDirection = vPorts[port_id++]; 771 TRACE_PORT(vPorts[port_id]); 772 cap->pSide = vPorts[port_id++]; 773 774 TRACE_PORT(vPorts[port_id]); 775 cap->pHeadCut = vPorts[port_id++]; 776 TRACE_PORT(vPorts[port_id]); 777 cap->pTailCut = vPorts[port_id++]; 778 TRACE_PORT(vPorts[port_id]); 779 cap->pFadeIn = vPorts[port_id++]; 780 TRACE_PORT(vPorts[port_id]); 781 cap->pFadeOut = vPorts[port_id++]; 782 TRACE_PORT(vPorts[port_id]); 783 cap->pListen = vPorts[port_id++]; 784 TRACE_PORT(vPorts[port_id]); 785 cap->pReverse = vPorts[port_id++]; 786 TRACE_PORT(vPorts[port_id]); 787 cap->pMakeup = vPorts[port_id++]; 788 TRACE_PORT(vPorts[port_id]); 789 cap->pStatus = vPorts[port_id++]; 790 TRACE_PORT(vPorts[port_id]); 791 cap->pLength = vPorts[port_id++]; 792 TRACE_PORT(vPorts[port_id]); 793 cap->pCurrLen = vPorts[port_id++]; 794 TRACE_PORT(vPorts[port_id]); 795 cap->pMaxLen = vPorts[port_id++]; 796 TRACE_PORT(vPorts[port_id]); 797 cap->pThumbs = vPorts[port_id++]; 798 799 TRACE_PORT(vPorts[port_id]); 800 cap->pOutFile = vPorts[port_id++]; 801 TRACE_PORT(vPorts[port_id]); 802 cap->pSaveCmd = vPorts[port_id++]; 803 TRACE_PORT(vPorts[port_id]); 804 cap->pSaveStatus = vPorts[port_id++]; 805 TRACE_PORT(vPorts[port_id]); 806 cap->pSaveProgress = vPorts[port_id++]; 807 808 TRACE_PORT(vPorts[port_id]); 809 port_id++; // Skip hue value 810 } 811 812 // Bind convolver ports 813 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 814 { 815 lsp_trace("Binding convolution #%d ports", int(i)); 816 convolver_t *c = &vConvolvers[i]; 817 818 if (nInputs > 1) // Input panning 819 { 820 TRACE_PORT(vPorts[port_id]); 821 c->pPanIn = vPorts[port_id++]; 822 } 823 824 TRACE_PORT(vPorts[port_id]); 825 c->pSample = vPorts[port_id++]; 826 TRACE_PORT(vPorts[port_id]); 827 c->pTrack = vPorts[port_id++]; 828 TRACE_PORT(vPorts[port_id]); 829 c->pMakeup = vPorts[port_id++]; 830 TRACE_PORT(vPorts[port_id]); 831 c->pMute = vPorts[port_id++]; 832 TRACE_PORT(vPorts[port_id]); 833 c->pActivity = vPorts[port_id++]; 834 TRACE_PORT(vPorts[port_id]); 835 c->pPredelay = vPorts[port_id++]; 836 TRACE_PORT(vPorts[port_id]); 837 c->pPanOut = vPorts[port_id++]; 838 } 839 840 // Bind wet processing ports 841 lsp_trace("Binding wet processing ports"); 842 size_t port = port_id; 843 for (size_t i=0; i<2; ++i) 844 { 845 channel_t *c = &vChannels[i]; 846 847 TRACE_PORT(vPorts[port_id]); 848 c->pWetEq = vPorts[port_id++]; 849 TRACE_PORT(vPorts[port_id]); 850 c->pLowCut = vPorts[port_id++]; 851 TRACE_PORT(vPorts[port_id]); 852 c->pLowFreq = vPorts[port_id++]; 853 854 for (size_t j=0; j<room_builder_base_metadata::EQ_BANDS; ++j) 855 { 856 TRACE_PORT(vPorts[port_id]); 857 c->pFreqGain[j] = vPorts[port_id++]; 858 } 859 860 TRACE_PORT(vPorts[port_id]); 861 c->pHighCut = vPorts[port_id++]; 862 TRACE_PORT(vPorts[port_id]); 863 c->pHighFreq = vPorts[port_id++]; 864 865 port_id = port; 866 } 867 } 868 destroy()869 void room_builder_base::destroy() 870 { 871 // Stop active rendering task 872 if (pRenderer != NULL) 873 { 874 pRenderer->terminate(); 875 pRenderer->join(); 876 delete pRenderer; 877 pRenderer = NULL; 878 } 879 880 sScene.destroy(); 881 s3DLoader.destroy(); 882 883 if (pData != NULL) 884 { 885 free_aligned(pData); 886 pData = NULL; 887 } 888 889 // Destroy captures 890 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 891 { 892 capture_t *c = &vCaptures[i]; 893 if (c->pCurr != NULL) 894 { 895 c->pCurr->destroy(); 896 delete c->pCurr; 897 c->pCurr = NULL; 898 } 899 if (c->pSwap != NULL) 900 { 901 c->pSwap->destroy(); 902 delete c->pSwap; 903 c->pSwap = NULL; 904 } 905 } 906 907 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 908 { 909 convolver_t *c = &vConvolvers[i]; 910 if (c->pCurr != NULL) 911 { 912 c->pCurr->destroy(); 913 delete c->pCurr; 914 c->pCurr = NULL; 915 } 916 if (c->pSwap != NULL) 917 { 918 c->pSwap->destroy(); 919 delete c->pSwap; 920 c->pSwap = NULL; 921 } 922 923 c->sDelay.destroy(); 924 } 925 926 // Destroy channels 927 for (size_t i=0; i<2; ++i) 928 { 929 channel_t *c = &vChannels[i]; 930 c->sEqualizer.destroy(); 931 c->sPlayer.destroy(false); 932 c->vOut = NULL; 933 c->vBuffer = NULL; 934 } 935 } 936 get_fft_rank(size_t rank)937 size_t room_builder_base::get_fft_rank(size_t rank) 938 { 939 return room_builder_base_metadata::FFT_RANK_MIN + rank; 940 } 941 update_settings()942 void room_builder_base::update_settings() 943 { 944 float out_gain = pOutGain->getValue(); 945 float dry_gain = pDry->getValue() * out_gain; 946 float wet_gain = pWet->getValue() * out_gain; 947 bool bypass = pBypass->getValue() >= 0.5f; 948 float predelay = pPredelay->getValue(); 949 size_t rank = get_fft_rank(pRank->getValue()); 950 951 // Adjust FFT rank 952 if (rank != nFftRank) 953 { 954 nFftRank = rank; 955 sConfigurator.queue_launch(); 956 } 957 958 // Adjust size of scene and number of threads to render 959 sScale.dx = pScaleX->getValue() * 0.01f; 960 sScale.dy = pScaleY->getValue() * 0.01f; 961 sScale.dz = pScaleZ->getValue() * 0.01f; 962 nRenderThreads = pRenderThreads->getValue(); 963 bRenderNormalize = pRenderNormalize->getValue() >= 0.5f; 964 fRenderQuality = pRenderQuality->getValue() * 0.01f; 965 966 // Check that render request has been triggered 967 float old_cmd = fRenderCmd; 968 fRenderCmd = pRenderCmd->getValue(); 969 if ((old_cmd >= 0.5f) && (fRenderCmd < 0.5f)) 970 { 971 lsp_trace("Triggered render request"); 972 nSync |= SYNC_TOGGLE_RENDER; 973 } 974 975 // Adjust volume of dry channel 976 if (nInputs == 1) 977 { 978 float pan = vInputs[0].pPan->getValue(); 979 vChannels[0].fDryPan[0] = (100.0f - pan) * 0.005f * dry_gain; 980 vChannels[0].fDryPan[1] = 0.0f; 981 vChannels[1].fDryPan[0] = (100.0f + pan) * 0.005f * dry_gain; 982 vChannels[1].fDryPan[1] = 0.0f; 983 } 984 else 985 { 986 float pan_l = vInputs[0].pPan->getValue(); 987 float pan_r = vInputs[1].pPan->getValue(); 988 989 vChannels[0].fDryPan[0] = (100.0f - pan_l) * 0.005f * dry_gain; 990 vChannels[0].fDryPan[1] = (100.0f - pan_r) * 0.005f * dry_gain; 991 vChannels[1].fDryPan[0] = (100.0f + pan_l) * 0.005f * dry_gain; 992 vChannels[1].fDryPan[1] = (100.0f + pan_r) * 0.005f * dry_gain; 993 } 994 995 // Update source settings 996 for (size_t i=0; i<room_builder_base_metadata::SOURCES; ++i) 997 { 998 source_t *src = &vSources[i]; 999 src->bEnabled = src->pEnabled->getValue() >= 0.5f; 1000 src->enType = decode_source_type(src->pType->getValue()); 1001 src->sPos.x = src->pPosX->getValue(); 1002 src->sPos.y = src->pPosY->getValue(); 1003 src->sPos.z = src->pPosZ->getValue(); 1004 src->sPos.w = 1.0f; 1005 src->fYaw = src->pYaw->getValue(); 1006 src->fPitch = src->pPitch->getValue(); 1007 src->fRoll = src->pRoll->getValue(); 1008 src->fSize = src->pSize->getValue() * 0.01f; // cm -> m 1009 src->fHeight = src->pHeight->getValue() * 0.01f; // cm -> m 1010 src->fAngle = src->pAngle->getValue(); 1011 src->fCurvature = src->pCurvature->getValue(); 1012 src->fAmplitude = (src->pPhase->getValue() >= 0.5f) ? -1.0f : 1.0f; 1013 } 1014 1015 // Update capture settings 1016 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1017 { 1018 capture_t *cap = &vCaptures[i]; 1019 1020 cap->bEnabled = cap->pEnabled->getValue() >= 0.5f; 1021 cap->nRMin = ssize_t(cap->pRMin->getValue()) - 1; 1022 cap->nRMax = ssize_t(cap->pRMax->getValue()) - 1; 1023 cap->sPos.x = cap->pPosX->getValue(); 1024 cap->sPos.y = cap->pPosY->getValue(); 1025 cap->sPos.z = cap->pPosZ->getValue(); 1026 cap->sPos.w = 1.0f; 1027 cap->fYaw = cap->pYaw->getValue(); 1028 cap->fPitch = cap->pPitch->getValue(); 1029 cap->fRoll = cap->pRoll->getValue(); 1030 cap->fCapsule = cap->pCapsule->getValue() * 0.5f; 1031 cap->sConfig = decode_config(cap->pConfig->getValue()); 1032 cap->fAngle = cap->pAngle->getValue(); 1033 cap->fDistance = cap->pDistance->getValue(); 1034 cap->enDirection = decode_direction(cap->pDirection->getValue()); 1035 cap->enSide = decode_side_direction(cap->pSide->getValue()); 1036 cap->fMakeup = cap->pMakeup->getValue(); 1037 1038 // Accept changes 1039 path_t *path = cap->pOutFile->getBuffer<path_t>(); 1040 if ((path != NULL) && (path->pending())) 1041 { 1042 path->accept(); 1043 path->commit(); 1044 } 1045 if (cap->pSaveCmd->getValue() >= 0.5f) // Toggle the export flag 1046 cap->bExport = true; 1047 1048 // Check that we need to synchronize capture settings with convolver 1049 float hcut = cap->pHeadCut->getValue(); 1050 float tcut = cap->pTailCut->getValue(); 1051 float fadein = cap->pFadeIn->getValue(); 1052 float fadeout = cap->pFadeOut->getValue(); 1053 bool reverse = cap->pReverse->getValue() >= 0.5f; 1054 1055 if ((cap->fHeadCut != hcut) || 1056 (cap->fTailCut != tcut) || 1057 (cap->fFadeIn != fadein) || 1058 (cap->fFadeOut != fadeout) || 1059 (cap->bReverse != reverse)) 1060 { 1061 cap->fHeadCut = hcut; 1062 cap->fTailCut = tcut; 1063 cap->fFadeIn = fadein; 1064 cap->fFadeOut = fadeout; 1065 cap->bReverse = reverse; 1066 1067 atomic_add(&cap->nChangeReq, 1); 1068 sConfigurator.queue_launch(); 1069 } 1070 1071 // Listen button pressed? 1072 if (cap->pListen->getValue() >= 0.5f) 1073 { 1074 size_t n_c = (cap->pCurr != NULL) ? cap->pCurr->channels() : 0; 1075 if (n_c > 0) 1076 { 1077 for (size_t j=0; j<2; ++j) 1078 vChannels[j].sPlayer.play(i, j % n_c, cap->fMakeup, 0); 1079 } 1080 } 1081 } 1082 1083 // Adjust channel setup 1084 for (size_t i=0; i<2; ++i) 1085 { 1086 channel_t *c = &vChannels[i]; 1087 c->sBypass.set_bypass(bypass); 1088 c->sPlayer.set_gain(out_gain); 1089 1090 // Update equalization parameters 1091 Equalizer *eq = &c->sEqualizer; 1092 equalizer_mode_t eq_mode = (c->pWetEq->getValue() >= 0.5f) ? EQM_IIR : EQM_BYPASS; 1093 eq->set_mode(eq_mode); 1094 1095 if (eq_mode != EQM_BYPASS) 1096 { 1097 filter_params_t fp; 1098 size_t band = 0; 1099 1100 // Set-up parametric equalizer 1101 while (band < room_builder_base_metadata::EQ_BANDS) 1102 { 1103 if (band == 0) 1104 { 1105 fp.fFreq = band_freqs[band]; 1106 fp.fFreq2 = fp.fFreq; 1107 fp.nType = FLT_MT_LRX_LOSHELF; 1108 } 1109 else if (band == (room_builder_base_metadata::EQ_BANDS - 1)) 1110 { 1111 fp.fFreq = band_freqs[band-1]; 1112 fp.fFreq2 = fp.fFreq; 1113 fp.nType = FLT_MT_LRX_HISHELF; 1114 } 1115 else 1116 { 1117 fp.fFreq = band_freqs[band-1]; 1118 fp.fFreq2 = band_freqs[band]; 1119 fp.nType = FLT_MT_LRX_LADDERPASS; 1120 } 1121 1122 fp.fGain = c->pFreqGain[band]->getValue(); 1123 fp.nSlope = 2; 1124 fp.fQuality = 0.0f; 1125 1126 // Update filter parameters 1127 eq->set_params(band++, &fp); 1128 } 1129 1130 // Setup hi-pass filter 1131 size_t hp_slope = c->pLowCut->getValue() * 2; 1132 fp.nType = (hp_slope > 0) ? FLT_BT_BWC_HIPASS : FLT_NONE; 1133 fp.fFreq = c->pLowFreq->getValue(); 1134 fp.fFreq2 = fp.fFreq; 1135 fp.fGain = 1.0f; 1136 fp.nSlope = hp_slope; 1137 fp.fQuality = 0.0f; 1138 eq->set_params(band++, &fp); 1139 1140 // Setup low-pass filter 1141 size_t lp_slope = c->pHighCut->getValue() * 2; 1142 fp.nType = (lp_slope > 0) ? FLT_BT_BWC_LOPASS : FLT_NONE; 1143 fp.fFreq = c->pHighFreq->getValue(); 1144 fp.fFreq2 = fp.fFreq; 1145 fp.fGain = 1.0f; 1146 fp.nSlope = lp_slope; 1147 fp.fQuality = 0.0f; 1148 eq->set_params(band++, &fp); 1149 } 1150 } 1151 1152 // Update settings of convolvers 1153 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1154 { 1155 convolver_t *cv = &vConvolvers[i]; 1156 1157 // Allow to reconfigure convolver only when configuration task is in idle state 1158 size_t sampleid = cv->pSample->getValue(); 1159 size_t trackid = cv->pTrack->getValue(); 1160 1161 if ((cv->nSampleID != sampleid) || 1162 (cv->nTrackID != trackid)) 1163 { 1164 cv->nSampleID = sampleid; 1165 cv->nTrackID = trackid; 1166 sConfigurator.queue_launch(); 1167 } 1168 1169 // Apply panning to each convolver 1170 float smakeup = (sampleid > 0) ? vCaptures[sampleid-1].fMakeup : 1.0f; // Sample makeup 1171 float makeup = (cv->pMute->getValue() < 0.5f) ? cv->pMakeup->getValue() * wet_gain * smakeup : 0.0f; 1172 if (nInputs == 1) 1173 { 1174 cv->fPanIn[0] = 1.0f; 1175 cv->fPanIn[1] = 0.0f; 1176 } 1177 else 1178 { 1179 float pan = cv->pPanIn->getValue(); 1180 cv->fPanIn[0] = (100.0f - pan) * 0.005f; 1181 cv->fPanIn[1] = (100.0f + pan) * 0.005f; 1182 } 1183 1184 float pan = cv->pPanOut->getValue(); 1185 cv->fPanOut[0] = (100.0f - pan) * 0.005f * makeup; 1186 cv->fPanOut[1] = (100.0f + pan) * 0.005f * makeup; 1187 1188 // Set pre-delay 1189 cv->sDelay.set_delay(millis_to_samples(fSampleRate, predelay + cv->pPredelay->getValue())); 1190 } 1191 } 1192 decode_source_type(float value)1193 rt_audio_source_t room_builder_base::decode_source_type(float value) 1194 { 1195 switch (ssize_t(value)) 1196 { 1197 case 1: return RT_AS_TETRA; 1198 case 2: return RT_AS_OCTA; 1199 case 3: return RT_AS_BOX; 1200 case 4: return RT_AS_ICO; 1201 case 5: return RT_AS_CYLINDER; 1202 case 6: return RT_AS_CONE; 1203 case 7: return RT_AS_OCTASPHERE; 1204 case 8: return RT_AS_ICOSPHERE; 1205 case 9: return RT_AS_FSPOT; 1206 case 10: return RT_AS_CSPOT; 1207 case 11: return RT_AS_SSPOT; 1208 default: break; 1209 } 1210 return RT_AS_TRIANGLE; 1211 } 1212 decode_config(float value)1213 rt_capture_config_t room_builder_base::decode_config(float value) 1214 { 1215 switch (ssize_t(value)) 1216 { 1217 case 1: return RT_CC_XY; 1218 case 2: return RT_CC_AB; 1219 case 3: return RT_CC_ORTF; 1220 case 4: return RT_CC_MS; 1221 default: break; 1222 } 1223 return RT_CC_MONO; 1224 } 1225 decode_direction(float value)1226 rt_audio_capture_t room_builder_base::decode_direction(float value) 1227 { 1228 switch (ssize_t(value)) 1229 { 1230 case 1: return RT_AC_SCARDIO; break; 1231 case 2: return RT_AC_HCARDIO; break; 1232 case 3: return RT_AC_BIDIR; break; 1233 case 4: return RT_AC_EIGHT; break; 1234 case 5: return RT_AC_OMNI; break; 1235 default: break; 1236 } 1237 return RT_AC_CARDIO; 1238 } 1239 decode_side_direction(float value)1240 rt_audio_capture_t room_builder_base::decode_side_direction(float value) 1241 { 1242 switch (ssize_t(value)) 1243 { 1244 case 1: return RT_AC_EIGHT; 1245 default: break; 1246 } 1247 return RT_AC_BIDIR; 1248 } 1249 update_sample_rate(long sr)1250 void room_builder_base::update_sample_rate(long sr) 1251 { 1252 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1253 vConvolvers[i].sDelay.init(millis_to_samples(sr, room_builder_base_metadata::PREDELAY_MAX * 4.0f)); 1254 1255 for (size_t i=0; i<2; ++i) 1256 { 1257 vChannels[i].sBypass.init(sr); 1258 vChannels[i].sEqualizer.set_sample_rate(sr); 1259 } 1260 } 1261 process(size_t samples)1262 void room_builder_base::process(size_t samples) 1263 { 1264 // Stage 1: Process reconfiguration requests and file events 1265 sync_offline_tasks(); 1266 1267 // Stage 2: Main processing 1268 for (size_t i=0; i<nInputs; ++i) 1269 vInputs[i].vIn = vInputs[i].pIn->getBuffer<float>(); 1270 1271 for (size_t i=0; i<2; ++i) 1272 vChannels[i].vOut = vChannels[i].pOut->getBuffer<float>(); 1273 1274 // Process samples 1275 while (samples > 0) 1276 { 1277 // Determine number of samples to process 1278 size_t to_do = TMP_BUF_SIZE; 1279 if (to_do > samples) 1280 to_do = samples; 1281 1282 // Clear temporary channel buffer 1283 dsp::fill_zero(vChannels[0].vBuffer, to_do); 1284 dsp::fill_zero(vChannels[1].vBuffer, to_do); 1285 1286 // Call convolvers 1287 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1288 { 1289 convolver_t *c = &vConvolvers[i]; 1290 1291 // Prepare input buffer: apply panning if present 1292 if (nInputs == 1) 1293 dsp::copy(c->vBuffer, vInputs[0].vIn, to_do); 1294 else 1295 dsp::mix_copy2(c->vBuffer, vInputs[0].vIn, vInputs[1].vIn, c->fPanIn[0], c->fPanIn[1], to_do); 1296 1297 // Do processing 1298 if (c->pCurr != NULL) 1299 c->pCurr->process(c->vBuffer, c->vBuffer, to_do); 1300 else 1301 dsp::fill_zero(c->vBuffer, to_do); 1302 c->sDelay.process(c->vBuffer, c->vBuffer, to_do); 1303 1304 // Apply processed signal to output channels 1305 dsp::fmadd_k3(vChannels[0].vBuffer, c->vBuffer, c->fPanOut[0], to_do); 1306 dsp::fmadd_k3(vChannels[1].vBuffer, c->vBuffer, c->fPanOut[1], to_do); 1307 } 1308 1309 // Now apply equalization, bypass control and players 1310 for (size_t i=0; i<2; ++i) 1311 { 1312 channel_t *c = &vChannels[i]; 1313 1314 // Apply equalization 1315 c->sEqualizer.process(c->vBuffer, c->vBuffer, to_do); 1316 1317 // Pass dry sound to output channels 1318 if (nInputs == 1) 1319 dsp::fmadd_k3(c->vBuffer, vInputs[0].vIn, c->fDryPan[0], to_do); 1320 else 1321 dsp::mix_add2(c->vBuffer, vInputs[0].vIn, vInputs[1].vIn, c->fDryPan[0], c->fDryPan[1], to_do); 1322 1323 // Apply player and bypass 1324 c->sPlayer.process(c->vBuffer, c->vBuffer, to_do); 1325 c->sBypass.process(c->vOut, vInputs[i%nInputs].vIn, c->vBuffer, to_do); 1326 1327 // Update pointers 1328 c->vOut += to_do; 1329 } 1330 1331 for (size_t i=0; i<nInputs; ++i) 1332 vInputs[i].vIn += to_do; 1333 1334 samples -= to_do; 1335 } 1336 1337 // Stage 3: output additional metering parameters 1338 if (p3DStatus != NULL) 1339 p3DStatus->setValue(nSceneStatus); 1340 if (p3DProgress != NULL) 1341 p3DProgress->setValue(fSceneProgress); 1342 if (pRenderStatus != NULL) 1343 pRenderStatus->setValue(enRenderStatus); 1344 if (pRenderProgress != NULL) 1345 pRenderProgress->setValue(fRenderProgress); 1346 1347 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1348 { 1349 // Output information about the convolver 1350 convolver_t *c = &vConvolvers[i]; 1351 c->pActivity->setValue(c->pCurr != NULL); 1352 } 1353 1354 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1355 { 1356 capture_t *c = &vCaptures[i]; 1357 1358 // Output information about the file 1359 size_t length = c->nLength; 1360 c->pLength->setValue(samples_to_millis(fSampleRate, length)); 1361 c->pCurrLen->setValue(c->fCurrLen); 1362 c->pMaxLen->setValue(c->fMaxLen); 1363 c->pStatus->setValue(c->nStatus); 1364 1365 // Store file dump to mesh 1366 mesh_t *mesh = c->pThumbs->getBuffer<mesh_t>(); 1367 if ((mesh == NULL) || (!mesh->isEmpty()) || (!c->bSync)) 1368 continue; 1369 1370 size_t channels = (c->pCurr != NULL) ? c->pCurr->channels() : 0; 1371 if (channels > 0) 1372 { 1373 // Copy thumbnails 1374 for (size_t j=0; j<channels; ++j) 1375 dsp::copy(mesh->pvData[j], c->vThumbs[j], room_builder_base_metadata::MESH_SIZE); 1376 mesh->data(channels, room_builder_base_metadata::MESH_SIZE); 1377 } 1378 else 1379 mesh->data(0, 0); 1380 c->bSync = false; 1381 } 1382 } 1383 sync_offline_tasks()1384 void room_builder_base::sync_offline_tasks() 1385 { 1386 // The render signal is pending? 1387 if ((nSync & SYNC_TOGGLE_RENDER) && (s3DLauncher.idle()) && (s3DLoader.idle())) 1388 { 1389 if (pExecutor->submit(&s3DLauncher)) 1390 { 1391 lsp_trace("Successfully submitted Render launcher task"); 1392 nSync &= ~SYNC_TOGGLE_RENDER; // Reset render request flag 1393 } 1394 } 1395 else if (s3DLauncher.completed()) 1396 { 1397 status_t res = s3DLauncher.code(); 1398 if (res != STATUS_OK) 1399 { 1400 fRenderProgress = 0.0f; 1401 enRenderStatus = s3DLauncher.code(); 1402 } 1403 s3DLauncher.reset(); 1404 } 1405 1406 // Check the state of input file 1407 path_t *path = p3DFile->getBuffer<path_t>(); 1408 if (path != NULL) 1409 { 1410 if ((path->pending()) && (s3DLoader.idle()) && (s3DLauncher.idle())) // There is pending request for 3D file reload 1411 { 1412 // Copy path 1413 ::strncpy(s3DLoader.sPath, path->get_path(), PATH_MAX); 1414 s3DLoader.nFlags = path->get_flags(); 1415 s3DLoader.sPath[PATH_MAX] = '\0'; 1416 lsp_trace("Submitted scene file %s", s3DLoader.sPath); 1417 1418 // Try to submit task 1419 if (pExecutor->submit(&s3DLoader)) 1420 { 1421 lsp_trace("Successfully submitted load task"); 1422 nSceneStatus = STATUS_LOADING; 1423 fSceneProgress = 0.0f; 1424 path->accept(); 1425 } 1426 } 1427 else if ((path->accepted()) && (s3DLoader.completed())) // The reload request has been processed 1428 { 1429 // Update file status and set re-rendering flag 1430 nSceneStatus = s3DLoader.code(); 1431 fSceneProgress = 100.0f; 1432 1433 sScene.swap(&s3DLoader.sScene); 1434 nReconfigReq ++; 1435 1436 // Now we surely can commit changes and reset task state 1437 lsp_trace("File loading task has completed with status %d", int(nSceneStatus)); 1438 path->commit(); 1439 s3DLoader.reset(); 1440 } 1441 } 1442 1443 if (sSaver.idle()) 1444 { 1445 // Submit save requests 1446 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1447 { 1448 capture_t *cap = &vCaptures[i]; 1449 if (!cap->bExport) 1450 continue; 1451 1452 sSaver.bind(i, cap); 1453 if (pExecutor->submit(&sSaver)) 1454 { 1455 cap->bExport = false; 1456 cap->pSaveStatus->setValue(STATUS_LOADING); 1457 cap->pSaveProgress->setValue(0.0f); 1458 break; 1459 } 1460 } 1461 } 1462 else if (sSaver.completed()) 1463 { 1464 capture_t *cap = &vCaptures[sSaver.nSampleID]; 1465 cap->pSaveStatus->setValue(sSaver.code()); 1466 cap->pSaveProgress->setValue(100.0f); 1467 1468 sSaver.reset(); 1469 } 1470 1471 // Do we need to launch configurator task? 1472 if ((sConfigurator.idle()) && (sConfigurator.need_launch())) 1473 { 1474 reconfig_t *cfg = &sConfigurator.sConfig; 1475 1476 // Deploy actual configuration to the configurator 1477 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1478 { 1479 capture_t *cap = &vCaptures[i]; 1480 size_t req = cap->nChangeReq; 1481 1482 cfg->bReconfigure[i] = (cap->nChangeResp != req); 1483 cfg->nChangeResp[i] = req; 1484 } 1485 1486 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1487 { 1488 convolver_t *cv = &vConvolvers[i]; 1489 1490 cfg->nSampleID[i] = cv->nSampleID; 1491 cfg->nTrack[i] = cv->nTrackID; 1492 cfg->nRank[i] = nFftRank; 1493 } 1494 1495 // Try to launch configurator 1496 if (pExecutor->submit(&sConfigurator)) 1497 { 1498 sConfigurator.launched(); 1499 lsp_trace("Successfully submitted reconfigurator task"); 1500 } 1501 } 1502 else if ((sConfigurator.completed()) && (sSaver.idle())) 1503 { 1504 lsp_trace("Reconfiguration task has completed with status %d", int(sConfigurator.code())); 1505 1506 // Commit state of convolvers 1507 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1508 { 1509 convolver_t *c = &vConvolvers[i]; 1510 Convolver *cv = c->pCurr; 1511 c->pCurr = c->pSwap; 1512 c->pSwap = cv; 1513 } 1514 1515 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1516 { 1517 capture_t *c = &vCaptures[i]; 1518 if (!c->bCommit) 1519 continue; 1520 1521 c->bCommit = false; 1522 c->bSync = true; 1523 1524 Sample *s = c->pCurr; 1525 c->pCurr = c->pSwap; 1526 c->pSwap = s; 1527 1528 // Bind sample player 1529 for (size_t j=0; j<2; ++j) 1530 { 1531 channel_t *sc = &vChannels[j]; 1532 sc->sPlayer.bind(i, c->pCurr, false); 1533 } 1534 } 1535 1536 // Accept the configurator task 1537 sConfigurator.reset(); 1538 } 1539 } 1540 bind_sources(RayTrace3D * rt)1541 status_t room_builder_base::bind_sources(RayTrace3D *rt) 1542 { 1543 size_t sources = 0; 1544 1545 for (size_t i=0; i<room_builder_base_metadata::SOURCES; ++i) 1546 { 1547 source_t *src = &vSources[i]; 1548 if (!src->bEnabled) 1549 continue; 1550 1551 // Configure source 1552 rt_source_settings_t ss; 1553 status_t res = rt_configure_source(&ss, src); 1554 if (res != STATUS_OK) 1555 return res; 1556 1557 // Add source to capture 1558 res = rt->add_source(&ss); 1559 if (res != STATUS_OK) 1560 return res; 1561 1562 ++sources; 1563 } 1564 1565 return (sources <= 0) ? STATUS_NO_SOURCES : STATUS_OK; 1566 } 1567 bind_captures(cvector<sample_t> & samples,RayTrace3D * rt)1568 status_t room_builder_base::bind_captures(cvector<sample_t> &samples, RayTrace3D *rt) 1569 { 1570 size_t captures = 0; 1571 1572 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1573 { 1574 capture_t *cap = &vCaptures[i]; 1575 if (!cap->bEnabled) 1576 continue; 1577 else if ((cap->nRMax >= 0) && (cap->nRMax < cap->nRMin)) // Validate nRMin and nRMax 1578 continue; 1579 1580 // Configure capture 1581 size_t n = 0; 1582 rt_capture_settings_t cs[2]; 1583 status_t res = rt_configure_capture(&n, cs, cap); 1584 if (res != STATUS_OK) 1585 return res; 1586 1587 // Create sample, add to list and initialize 1588 sample_t *s = new sample_t(); 1589 if (s == NULL) 1590 return STATUS_NO_MEM; 1591 else if (!samples.add(s)) 1592 { 1593 delete s; 1594 return STATUS_NO_MEM; 1595 } 1596 s->nID = i; 1597 s->enConfig = cap->sConfig; 1598 if (!s->sSample.init(n, 512)) 1599 return STATUS_NO_MEM; 1600 1601 // Bind captures to samples 1602 for (size_t i=0; i<n; ++i) 1603 { 1604 ssize_t cap_id = rt->add_capture(&cs[i]); 1605 if (cap_id < 0) 1606 return status_t(-cap_id); 1607 1608 res = rt->bind_capture(cap_id, &s->sSample, i, cap->nRMin, cap->nRMax); 1609 if (res != STATUS_OK) 1610 return res; 1611 1612 ++captures; 1613 } 1614 } 1615 1616 return (captures <= 0) ? STATUS_NO_CAPTURES : STATUS_OK; 1617 } 1618 destroy_samples(cvector<sample_t> & samples)1619 void room_builder_base::destroy_samples(cvector<sample_t> &samples) 1620 { 1621 for (size_t i=0, n=samples.size(); i<n; ++i) 1622 { 1623 sample_t *s = samples.at(i); 1624 if (s != NULL) 1625 { 1626 s->sSample.destroy(); 1627 delete s; 1628 } 1629 } 1630 samples.flush(); 1631 } 1632 bind_scene(KVTStorage * kvt,RayTrace3D * rt)1633 status_t room_builder_base::bind_scene(KVTStorage *kvt, RayTrace3D *rt) 1634 { 1635 // Clone the scene 1636 Scene3D *dst = new Scene3D(); 1637 if (dst == NULL) 1638 return STATUS_NO_MEM; 1639 1640 status_t res = dst->clone_from(&sScene); 1641 if (res != STATUS_OK) 1642 { 1643 delete dst; 1644 return res; 1645 } 1646 1647 // Set-up scene 1648 res = rt->set_scene(dst, true); 1649 if (res != STATUS_OK) 1650 { 1651 dst->destroy(); 1652 delete dst; 1653 return res; 1654 } 1655 1656 // Update object properties 1657 obj_props_t props; 1658 char base[0x40]; 1659 rt_material_t mat; 1660 matrix3d_t world; 1661 dsp::init_matrix3d_scale(&world, sScale.dx, sScale.dy, sScale.dz); 1662 1663 for (size_t i=0, n=dst->num_objects(); i<n; ++i) 1664 { 1665 Object3D *obj = dst->object(i); 1666 if (obj == NULL) 1667 continue; 1668 1669 // Read object properties 1670 sprintf(base, "/scene/object/%d", int(i)); 1671 read_object_properties(&props, base, kvt); 1672 1673 // Update object matrix and visibility 1674 build_object_matrix(obj->matrix(), &props, &world); 1675 obj->set_visible(props.bEnabled); 1676 1677 // Initialize material 1678 mat.absorption[0] = props.fAbsorption[0] * 0.01f; // % -> units 1679 mat.absorption[1] = props.fAbsorption[1] * 0.01f; // % -> units 1680 mat.diffusion[0] = props.fDiffusion[0]; 1681 mat.diffusion[1] = props.fDiffusion[1]; 1682 mat.dispersion[0] = props.fDispersion[0]; 1683 mat.dispersion[1] = props.fDispersion[1]; 1684 mat.transparency[0] = props.fTransparency[0] * 0.01f; // % -> units 1685 mat.transparency[1] = props.fTransparency[1] * 0.01f; // % -> units 1686 mat.permeability = props.fSndSpeed / SOUND_SPEED_M_S; 1687 1688 // Commit material properties 1689 res = rt->set_material(i, &mat); 1690 if (res != STATUS_OK) 1691 return res; 1692 } 1693 1694 return STATUS_OK; 1695 } 1696 progress_callback(float progress,void * ptr)1697 status_t room_builder_base::progress_callback(float progress, void *ptr) 1698 { 1699 room_builder_base *_this = reinterpret_cast<room_builder_base *>(ptr); 1700 _this->enRenderStatus = STATUS_IN_PROCESS; 1701 _this->fRenderProgress = progress * 100.0f; // Update the progress value 1702 return STATUS_OK; 1703 } 1704 start_rendering()1705 status_t room_builder_base::start_rendering() 1706 { 1707 // Terminate previous thread (if active) 1708 if (pRenderer != NULL) 1709 { 1710 bool finished = pRenderer->finished(); 1711 1712 pRenderer->terminate(); 1713 pRenderer->join(); 1714 delete pRenderer; 1715 pRenderer = NULL; 1716 1717 // Current task has been cancelled? 1718 if (!finished) 1719 { 1720 fRenderProgress = 0; 1721 enRenderStatus = STATUS_CANCELLED; 1722 return STATUS_OK; 1723 } 1724 } 1725 1726 // Create raytracing object and initialize with basic values 1727 RayTrace3D *rt = new RayTrace3D(); 1728 if (rt == NULL) 1729 return STATUS_NO_MEM; 1730 1731 status_t res = rt->init(); 1732 if (res != STATUS_OK) 1733 { 1734 rt->destroy(false); 1735 delete rt; 1736 return res; 1737 } 1738 1739 rt->set_sample_rate(fSampleRate); 1740 1741 float energy = 1e-3f * expf(-4.0f * M_LN10 * fRenderQuality); // 1e-3 .. 1e-7 1742 float tolerance = 1e-4f * expf(-2.0f * M_LN10 * fRenderQuality); // 1e-4 .. 1e-6 1743 float details = 1e-8f * expf(-2.0f * M_LN10 * fRenderQuality); // 1e-8 .. 1e-10 1744 1745 rt->set_energy_threshold(energy); 1746 rt->set_tolerance(tolerance); 1747 rt->set_detalization(details); 1748 rt->set_normalize(bRenderNormalize); 1749 rt->set_progress_callback(progress_callback, this); 1750 1751 // Bind scene to the raytracing 1752 KVTStorage *kvt = kvt_lock(); 1753 if (kvt != NULL) 1754 { 1755 res = bind_scene(kvt, rt); 1756 kvt_release(); 1757 } 1758 else 1759 res = STATUS_NO_DATA; 1760 1761 // Bind sources 1762 res = bind_sources(rt); 1763 if (res != STATUS_OK) 1764 { 1765 rt->destroy(true); 1766 delete rt; 1767 return res; 1768 } 1769 1770 // Bind captures 1771 cvector<sample_t> samples; 1772 res = bind_captures(samples, rt); 1773 if (res != STATUS_OK) 1774 { 1775 destroy_samples(samples); 1776 rt->destroy(true); 1777 delete rt; 1778 return res; 1779 } 1780 1781 // Create renderer and start execution 1782 if (res == STATUS_OK) 1783 { 1784 pRenderer = new Renderer(this, rt, nRenderThreads, samples); 1785 if (pRenderer == NULL) 1786 res = STATUS_NO_MEM; 1787 else if ((res = pRenderer->start()) != STATUS_OK) 1788 { 1789 delete pRenderer; 1790 pRenderer = NULL; 1791 } 1792 } 1793 1794 if (res != STATUS_OK) 1795 { 1796 destroy_samples(samples); 1797 rt->destroy(true); 1798 delete rt; 1799 return res; 1800 } 1801 1802 // All seems to be OK 1803 return STATUS_OK; 1804 } 1805 commit_samples(cvector<sample_t> & samples)1806 status_t room_builder_base::commit_samples(cvector<sample_t> &samples) 1807 { 1808 // Put each sample to KVT and toggle the reload flag 1809 kvt_param_t p; 1810 char path[0x40]; 1811 1812 for (size_t i=0, n=samples.size(); i<n; ++i) 1813 { 1814 sample_t *s = samples.at(i); 1815 if (s == NULL) 1816 continue; 1817 1818 // Create sample data 1819 size_t slen = s->sSample.length(); 1820 size_t payload = sizeof(sample_header_t) + slen * s->sSample.channels() * sizeof(float); 1821 sample_header_t *hdr = reinterpret_cast<sample_header_t *>(::malloc(payload)); 1822 if (hdr == NULL) 1823 return STATUS_NO_MEM; 1824 hdr->version = __IF_LEBE(0, 1); 1825 hdr->channels = s->sSample.channels(); 1826 hdr->sample_rate = fSampleRate; 1827 hdr->samples = s->sSample.length(); 1828 1829 hdr->version = CPU_TO_BE(hdr->version); 1830 hdr->channels = CPU_TO_BE(hdr->channels); 1831 hdr->sample_rate = CPU_TO_BE(hdr->sample_rate); 1832 hdr->samples = CPU_TO_BE(hdr->samples); 1833 1834 float *fdst = reinterpret_cast<float *>(&hdr[1]); 1835 for (size_t i=0; i<s->sSample.channels(); ++i, fdst += slen) 1836 ::memcpy(fdst, s->sSample.getBuffer(i), slen * sizeof(float)); 1837 1838 // Post-process Mid/Side audio data 1839 if (s->enConfig == RT_CC_MS) 1840 { 1841 float *l = reinterpret_cast<float *>(&hdr[1]); 1842 float *r = &l[slen]; 1843 dsp::ms_to_lr(l, r, l, r, slen); 1844 } 1845 1846 // Create KVT parameter 1847 p.type = KVT_BLOB; 1848 p.blob.ctype = ::strdup(AUDIO_SAMPLE_CONTENT_TYPE); 1849 if (p.blob.ctype == NULL) 1850 { 1851 ::free(hdr); 1852 return STATUS_NO_MEM; 1853 } 1854 p.blob.size = payload; 1855 p.blob.data = hdr; 1856 1857 // Deploy KVT parameter 1858 sprintf(path, "/samples/%d", int(s->nID)); 1859 KVTStorage *kvt = kvt_lock(); 1860 if (kvt != NULL) 1861 { 1862 kvt->put(path, &p, KVT_PRIVATE | KVT_DELEGATE); // Delegate memory management to KVT Storage 1863 kvt->gc(); 1864 kvt_release(); 1865 } 1866 else 1867 return STATUS_BAD_STATE; 1868 1869 // Update the number of changes for the sample and toggle configurator launch 1870 atomic_add(&vCaptures[s->nID].nChangeReq, 1); 1871 sConfigurator.queue_launch(); 1872 } 1873 1874 return STATUS_OK; 1875 } 1876 reconfigure(const reconfig_t * cfg)1877 status_t room_builder_base::reconfigure(const reconfig_t *cfg) 1878 { 1879 status_t res; 1880 1881 // Collect the garbage 1882 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 1883 { 1884 convolver_t *c = &vConvolvers[i]; 1885 if (c->pSwap != NULL) 1886 { 1887 c->pSwap->destroy(); 1888 delete c->pSwap; 1889 c->pSwap = NULL; 1890 } 1891 } 1892 1893 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1894 { 1895 capture_t *c = &vCaptures[i]; 1896 if (c->pSwap != NULL) 1897 { 1898 c->pSwap->destroy(); 1899 delete c->pSwap; 1900 c->pSwap = NULL; 1901 } 1902 } 1903 1904 // Re-render samples 1905 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 1906 { 1907 capture_t *c = &vCaptures[i]; 1908 1909 // Do we need to change the sample? 1910 if (!cfg->bReconfigure[i]) 1911 continue; 1912 1913 // Update status and commit request 1914 c->nStatus = STATUS_OK; 1915 c->nChangeResp = cfg->nChangeResp[i]; 1916 c->bCommit = true; 1917 1918 // Lock KVT and fetch sample data 1919 KVTStorage *kvt = kvt_lock(); 1920 if (kvt == NULL) 1921 { 1922 c->nStatus = STATUS_BAD_STATE; 1923 continue; 1924 } 1925 1926 // Fetch KVT sample 1927 sample_header_t hdr; 1928 const float *samples; 1929 res = fetch_kvt_sample(kvt, i, &hdr, &samples); 1930 if (res != STATUS_OK) 1931 { 1932 c->nStatus = res; 1933 kvt_release(); 1934 continue; 1935 } 1936 1937 // Allocate new sample 1938 Sample *s = new Sample(); 1939 if (s == NULL) 1940 { 1941 kvt_release(); 1942 c->nStatus = STATUS_NO_MEM; 1943 continue; 1944 } 1945 c->nLength = hdr.samples; 1946 c->fMaxLen = samples_to_millis(hdr.sample_rate, hdr.samples); 1947 c->pSwap = s; 1948 lsp_trace("Allocated sample=%p, original length=%d samples", s, int(c->nLength)); 1949 1950 // Initialize sample 1951 if (!s->init(hdr.channels, hdr.samples, hdr.samples)) 1952 { 1953 kvt_release(); 1954 c->nStatus = STATUS_NO_MEM; 1955 continue; 1956 } 1957 1958 // Sample is present, check boundaries 1959 size_t head_cut = millis_to_samples(fSampleRate, c->fHeadCut); 1960 size_t tail_cut = millis_to_samples(fSampleRate, c->fTailCut); 1961 ssize_t fsamples = hdr.samples - head_cut - tail_cut; 1962 if (fsamples <= 0) 1963 { 1964 s->setLength(0); 1965 c->fCurrLen = 0.0f; 1966 kvt_release(); 1967 1968 for (size_t j=0; j<hdr.channels; ++j) 1969 dsp::fill_zero(c->vThumbs[j], room_builder_base_metadata::MESH_SIZE); 1970 continue; 1971 } 1972 c->fCurrLen = samples_to_millis(hdr.sample_rate, fsamples); 1973 1974 // Render the sample 1975 float norm = 0.0f; 1976 for (size_t j=0; j<hdr.channels; ++j) 1977 { 1978 const float *src = &samples[j * hdr.samples]; 1979 float *dst = s->getBuffer(j); 1980 1981 // Get normalizing factor 1982 float xnorm = dsp::abs_max(src, hdr.samples); 1983 if (xnorm > norm) 1984 norm = xnorm; 1985 1986 // Copy sample data and apply fading 1987 if (c->bReverse) 1988 dsp::reverse2(dst, &src[tail_cut], fsamples); 1989 else 1990 dsp::copy(dst, &src[head_cut], fsamples); 1991 if ((hdr.version & 1) != __IF_LEBE(0, 1)) // Endianess does not match? 1992 byte_swap(dst, fsamples); 1993 1994 fade_in(dst, dst, millis_to_samples(fSampleRate, c->fFadeIn), fsamples); 1995 fade_out(dst, dst, millis_to_samples(fSampleRate, c->fFadeOut), fsamples); 1996 1997 // Now render thumbnail 1998 src = dst; 1999 dst = c->vThumbs[j]; 2000 for (size_t k=0; k<room_builder_base_metadata::MESH_SIZE; ++k) 2001 { 2002 size_t first = (k * fsamples) / room_builder_base_metadata::MESH_SIZE; 2003 size_t last = ((k + 1) * fsamples) / room_builder_base_metadata::MESH_SIZE; 2004 if (first < last) 2005 dst[k] = dsp::abs_max(&src[first], last - first); 2006 else 2007 dst[k] = fabs(src[first]); 2008 } 2009 } 2010 2011 // Normalize graph if possible 2012 if (norm != 0.0f) 2013 { 2014 norm = 1.0f / norm; 2015 for (size_t j=0; j<hdr.channels; ++j) 2016 dsp::mul_k2(c->vThumbs[j], norm, room_builder_base_metadata::MESH_SIZE); 2017 } 2018 2019 // Release KVT storage 2020 kvt_release(); 2021 } 2022 2023 // Randomize phase of the convolver 2024 uint32_t phase = seed_addr(this); 2025 phase = ((phase << 16) | (phase >> 16)) & 0x7fffffff; 2026 uint32_t step = 0x80000000 / (room_builder_base_metadata::CONVOLVERS + 1); 2027 2028 // Reconfigure convolvers 2029 for (size_t i=0; i<room_builder_base_metadata::CONVOLVERS; ++i) 2030 { 2031 convolver_t *c = &vConvolvers[i]; 2032 2033 // Check that routing has changed 2034 size_t capture = cfg->nSampleID[i]; 2035 size_t track = cfg->nTrack[i]; 2036 if ((capture <= 0) || (capture > room_builder_base_metadata::CAPTURES)) 2037 continue; 2038 else 2039 --capture; 2040 2041 // Analyze sample 2042 Sample *s = (vCaptures[capture].bCommit) ? vCaptures[capture].pSwap: vCaptures[capture].pCurr; 2043 if ((s == NULL) || (!s->valid()) || (s->channels() <= track)) 2044 continue; 2045 2046 // Now we can create convolver 2047 Convolver *cv = new Convolver(); 2048 if (!cv->init(s->getBuffer(track), s->length(), cfg->nRank[i], float((phase + i*step)& 0x7fffffff)/float(0x80000000))) 2049 { 2050 cv->destroy(); 2051 delete cv; 2052 return STATUS_NO_MEM; 2053 } 2054 2055 lsp_trace("Allocated convolver pSwap=%p for channel %d (pCurr=%p)", cv, int(i), c->pCurr); 2056 c->pSwap = cv; 2057 } 2058 2059 return STATUS_OK; 2060 } 2061 fetch_kvt_sample(KVTStorage * kvt,size_t sample_id,sample_header_t * hdr,const float ** samples)2062 status_t room_builder_base::fetch_kvt_sample(KVTStorage *kvt, size_t sample_id, sample_header_t *hdr, const float **samples) 2063 { 2064 status_t res; 2065 const kvt_param_t *p; 2066 const sample_header_t *phdr; 2067 char path[0x40]; 2068 2069 sprintf(path, "/samples/%d", int(sample_id)); 2070 2071 // Fetch parameter 2072 res = kvt->get(path, &p, KVT_BLOB); 2073 if ((res != STATUS_OK) || 2074 (p == NULL)) 2075 return STATUS_NO_DATA; 2076 2077 // Validate blob settings 2078 if ((p->blob.ctype == NULL) || 2079 (p->blob.data == NULL) || 2080 (p->blob.size < sizeof(sample_header_t)) || 2081 (::strcmp(p->blob.ctype, AUDIO_SAMPLE_CONTENT_TYPE) != 0)) 2082 return STATUS_CORRUPTED; 2083 2084 // Decode sample data 2085 phdr = reinterpret_cast<const sample_header_t *>(p->blob.data); 2086 hdr->version = BE_TO_CPU(phdr->version); 2087 hdr->channels = BE_TO_CPU(phdr->channels); 2088 hdr->sample_rate = BE_TO_CPU(phdr->sample_rate); 2089 hdr->samples = BE_TO_CPU(phdr->samples); 2090 2091 if (((hdr->version >> 1) != 0) || 2092 ((hdr->samples * hdr->channels * sizeof(float) + sizeof(sample_header_t)) != p->blob.size)) 2093 return STATUS_CORRUPTED; 2094 2095 *samples = reinterpret_cast<const float *>(&phdr[1]); 2096 return STATUS_OK; 2097 } 2098 save_sample(const char * path,size_t sample_id)2099 status_t room_builder_base::save_sample(const char *path, size_t sample_id) 2100 { 2101 if (::strlen(path) <= 0) 2102 return STATUS_BAD_PATH; 2103 2104 LSPString sp, lspc; 2105 if ((!sp.set_utf8(path)) || (!lspc.set_ascii(".lspc"))) 2106 return STATUS_NO_MEM; 2107 2108 // Lock KVT storage 2109 KVTStorage *kvt = kvt_lock(); 2110 if (kvt == NULL) 2111 return STATUS_BAD_STATE; 2112 2113 sample_header_t hdr; 2114 const float *samples; 2115 status_t res = fetch_kvt_sample(kvt, sample_id, &hdr, &samples); 2116 2117 // Check the extension of file 2118 if (sp.ends_with_nocase(&lspc)) 2119 { 2120 lspc_audio_parameters_t params; 2121 params.channels = hdr.channels; 2122 params.sample_format = (hdr.version & 1) ? LSPC_SAMPLE_FMT_F32BE : LSPC_SAMPLE_FMT_F32LE; 2123 params.sample_rate = hdr.sample_rate; 2124 params.codec = LSPC_CODEC_PCM; 2125 params.frames = hdr.samples; 2126 2127 // Initialize sample array 2128 const float **vs = reinterpret_cast<const float **>(::malloc(params.channels * sizeof(float *))); 2129 if (vs == NULL) 2130 { 2131 kvt_release(); 2132 return STATUS_NO_MEM; 2133 } 2134 for (size_t i=0; i<params.channels; ++i) 2135 vs[i] = &samples[i * params.frames]; 2136 2137 // Create LSPC writer 2138 LSPCAudioWriter wr; 2139 res = wr.create(&sp, ¶ms); 2140 if (res != STATUS_OK) 2141 { 2142 ::free(vs); 2143 kvt_release(); 2144 return res; 2145 } 2146 2147 // Write all samples to the file 2148 res = wr.write_samples(vs, params.frames); 2149 status_t res2 = wr.close(); 2150 if (res == STATUS_OK) 2151 res = res2; 2152 ::free(vs); 2153 } 2154 else 2155 { 2156 AudioFile af; 2157 res = af.create_samples(hdr.channels, hdr.sample_rate, hdr.samples); 2158 if (res != STATUS_OK) 2159 { 2160 kvt_release(); 2161 return res; 2162 } 2163 2164 // Prepare file contents 2165 for (size_t i=0; i<hdr.channels; ++i) 2166 { 2167 float *dst = af.channel(i); 2168 dsp::copy(dst, &samples[i * hdr.samples], hdr.samples); 2169 if ((hdr.version & 1) != __IF_LEBE(0, 1)) 2170 byte_swap(dst, hdr.samples); 2171 } 2172 2173 // Store file contents 2174 res = af.store(&sp); 2175 af.destroy(); 2176 } 2177 2178 // Release KVT storage and return result 2179 kvt_release(); 2180 return res; 2181 } 2182 state_loaded()2183 void room_builder_base::state_loaded() 2184 { 2185 // We need to sync all loaded samples in KVT with internal state 2186 for (size_t i=0; i<room_builder_base_metadata::CAPTURES; ++i) 2187 { 2188 capture_t *cap = &vCaptures[i]; 2189 atomic_add(&cap->nChangeReq, 1); 2190 sConfigurator.queue_launch(); 2191 } 2192 } 2193 ui_activated()2194 void room_builder_base::ui_activated() 2195 { 2196 // Synchronize thumbnails with UI 2197 for (size_t i=0; i<impulse_reverb_base_metadata::FILES; ++i) 2198 vCaptures[i].bSync = true; 2199 } 2200 2201 //------------------------------------------------------------------------- room_builder_mono()2202 room_builder_mono::room_builder_mono(): room_builder_base(metadata, 1) 2203 { 2204 } 2205 ~room_builder_mono()2206 room_builder_mono::~room_builder_mono() 2207 { 2208 } 2209 room_builder_stereo()2210 room_builder_stereo::room_builder_stereo(): room_builder_base(metadata, 2) 2211 { 2212 } 2213 ~room_builder_stereo()2214 room_builder_stereo::~room_builder_stereo() 2215 { 2216 } 2217 } 2218 2219