Sound_and_MixingMatrix.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /* Sound_and_MixingMatrix.cpp
  2. *
  3. * Copyright (C) 2010-2017 David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "Interpreter.h"
  19. #include "NUM2.h"
  20. #include "Sound_and_MixingMatrix.h"
  21. void Sound_MixingMatrix_playPart (Sound me, MixingMatrix thee, double fromTime, double toTime, Sound_PlayCallback callback, Thing boss) {
  22. try {
  23. autoSound mix = Sound_MixingMatrix_mixPart (me, thee, fromTime, toTime);
  24. Sound_playPart (mix.get(), fromTime, toTime, callback, boss);
  25. } catch (MelderError) {
  26. Melder_throw (me, U": not played.");
  27. }
  28. }
  29. void Sound_MixingMatrix_play (Sound me, MixingMatrix thee, Sound_PlayCallback callback, Thing boss) {
  30. Sound_MixingMatrix_playPart (me, thee, my xmin, my xmax, callback, boss);
  31. }
  32. autoSound Sound_MixingMatrix_mix (Sound me, MixingMatrix thee) {
  33. return Sound_MixingMatrix_mixPart (me, thee, my xmin, my xmax);
  34. }
  35. autoSound Sound_MixingMatrix_mixPart (Sound me, MixingMatrix thee, double fromTime, double toTime) {
  36. try {
  37. Melder_require (my ny == thy numberOfColumns,
  38. U"The number of inputs in the MixingMatrix and the number of channels in the Sound should be equal.");
  39. if (fromTime == toTime) {
  40. fromTime = my xmin; toTime = my xmax;
  41. }
  42. // Determine index range. We use all the real or virtual samples that fit within [fromTime..toTime].
  43. integer ix1 = 1 + Melder_iceiling ((fromTime - my x1) / my dx);
  44. integer ix2 = 1 + Melder_ifloor ((toTime - my x1) / my dx);
  45. if (ix2 < ix1) {
  46. Melder_throw (U"Mixed Sound would contain no samples.");
  47. }
  48. autoSound him = Sound_create (thy numberOfRows, fromTime, toTime, ix2 - ix1 + 1, my dx, my x1 + (ix1 - 1) * my dx);
  49. /*
  50. * 1 nx 1 nx
  51. * |..........| |..........| (me)
  52. * |-----------|---| |-----|----------| (index in me)
  53. * ix1 ix2 ix2 ix1 ix2 ix2
  54. * 1 'nx' 'nx'
  55. * Example: (1) (2) (3) (4)
  56. * New sound: him_nx = ix2 - ix1 + 1
  57. * Example: nx = 12
  58. * (1) copy from [1, ix2] to [2-ix1, 1 - ix1 + ix2]
  59. * ix1=-3, ix2=8 [1,8] -> [5,12]
  60. * (2) copy from [1, nx] to [2-ix1, 1 - ix1 + nx]
  61. * ix1=-3, ix2=13 [1,12] -> [5,16]
  62. * (3) copy from [ix1,ix2] to [1 , ix2 -ix1 + 1]
  63. * ix1=4, ix2=10 [4,10] -> [1,7]
  64. * (4) copy from [ix1, nx] to [1 , nx -ix1 + 1]
  65. * ix1=4, ix2=21 [4,12] -> [1,9]
  66. */
  67. if (! (toTime < my xmin || fromTime > my xmax)) {
  68. for (integer i = 1; i <= thy numberOfRows; i ++) {
  69. for (integer ichan = 1; ichan <= my ny; ichan ++) {
  70. double mixingCoeffient = thy data [i] [ichan];
  71. if (mixingCoeffient != 0.0) {
  72. double *from = my z [ichan], *to = his z [i];
  73. integer to_i1 = 1, to_i2 = his nx;
  74. if (ix1 < 1) { // (1) + (2)
  75. to = his z [i] + 1 - ix1;
  76. to_i1 = 1 - ix1; to_i2 = to_i1 + my nx; // (2)
  77. if (ix2 < my nx) { // (1)
  78. to_i2 = 1 - ix1 + ix2;
  79. }
  80. } else { // (3) + (4)
  81. from = my z [ichan] + ix1 - 1;
  82. to_i2 = to_i1 + ix2 - ix1; // (3)
  83. if (ix2 > my nx) { // (4)
  84. to_i2 = his nx;
  85. }
  86. }
  87. for (integer j = 1; j <= to_i2 - to_i1 + 1; j ++) {
  88. to [j] += mixingCoeffient * from [j];
  89. }
  90. }
  91. }
  92. }
  93. }
  94. return him;
  95. } catch (MelderError) {
  96. Melder_throw (me, U": not mixed.");
  97. }
  98. }
  99. autoSound Sound_MixingMatrix_unmix (Sound me, MixingMatrix thee) {
  100. try {
  101. Melder_require (my ny == thy numberOfColumns,
  102. U"The number of inputs in the MixingMatrix and the number of channels in the Sound should be equal.");
  103. autoMAT minv = MATzero (thy numberOfColumns, thy numberOfRows);
  104. NUMpseudoInverse (thy data.at, thy numberOfRows, thy numberOfColumns, minv.at, 0.0);
  105. autoSound him = Sound_create (thy numberOfColumns, my xmin, my xmax, my nx, my dx, my x1);
  106. for (integer i = 1; i <= thy numberOfColumns; i ++) {
  107. for (integer j = 1; j <= my nx; j ++) {
  108. longdouble s = 0.0;
  109. for (integer k = 1; k <= my ny; k ++)
  110. s += minv [i] [k] * my z [k] [j];
  111. his z [i] [j] = (double) s;
  112. }
  113. }
  114. return him;
  115. } catch (MelderError) {
  116. Melder_throw (me, U": not unmixed.");
  117. }
  118. }
  119. /* End of file Sound_and_MixingMatrix.cpp */