jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

451 lines
12KB

  1. /*
  2. Copyright (C) 2004-2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #ifndef __JackConnectionManager__
  16. #define __JackConnectionManager__
  17. #include "JackConstants.h"
  18. #include "JackActivationCount.h"
  19. #include <assert.h>
  20. namespace Jack
  21. {
  22. struct JackClientControl;
  23. /*!
  24. \brief Utility class.
  25. */
  26. template <int SIZE>
  27. class JackFixedArray
  28. {
  29. private:
  30. jack_int_t fTable[SIZE];
  31. uint32_t fCounter;
  32. public:
  33. JackFixedArray()
  34. {
  35. Init();
  36. }
  37. virtual ~JackFixedArray()
  38. {}
  39. void Init()
  40. {
  41. for (int i = 0; i < SIZE; i++)
  42. fTable[i] = EMPTY;
  43. fCounter = 0;
  44. }
  45. bool AddItem(jack_int_t index)
  46. {
  47. for (int i = 0; i < SIZE; i++) {
  48. if (fTable[i] == EMPTY) {
  49. fTable[i] = index;
  50. fCounter++;
  51. return true;
  52. }
  53. }
  54. return false;
  55. }
  56. bool RemoveItem(jack_int_t index)
  57. {
  58. for (int i = 0; i < SIZE; i++) {
  59. if (fTable[i] == index) {
  60. fCounter--;
  61. // Shift all indexes
  62. if (i == SIZE - 1) {
  63. fTable[i] = EMPTY;
  64. } else {
  65. int j;
  66. for (j = i; j <= SIZE - 2 && fTable[j] != EMPTY; j++) {
  67. fTable[j] = fTable[j + 1];
  68. }
  69. fTable[j] = EMPTY;
  70. }
  71. return true;
  72. }
  73. }
  74. return false;
  75. }
  76. jack_int_t GetItem(jack_int_t index) const
  77. {
  78. return (index < SIZE) ? fTable[index] : EMPTY;
  79. }
  80. const jack_int_t* GetItems() const
  81. {
  82. return fTable;
  83. }
  84. bool CheckItem(jack_int_t index) const
  85. {
  86. for (int i = 0; i < SIZE && fTable[i] != EMPTY; i++) {
  87. if (fTable[i] == index)
  88. return true;
  89. }
  90. return false;
  91. }
  92. uint32_t GetItemCount() const
  93. {
  94. return fCounter;
  95. }
  96. };
  97. /*!
  98. \brief Utility class.
  99. */
  100. template <int SIZE>
  101. class JackFixedArray1 : public JackFixedArray<SIZE>
  102. {
  103. private:
  104. bool fUsed;
  105. public:
  106. JackFixedArray1()
  107. {
  108. Init();
  109. }
  110. virtual ~JackFixedArray1()
  111. {}
  112. void Init()
  113. {
  114. JackFixedArray<SIZE>::Init();
  115. fUsed = false;
  116. }
  117. bool IsAvailable()
  118. {
  119. if (fUsed) {
  120. return false;
  121. } else {
  122. fUsed = true;
  123. return true;
  124. }
  125. }
  126. };
  127. /*!
  128. \brief Utility class.
  129. */
  130. template <int SIZE>
  131. class JackFixedMatrix
  132. {
  133. private:
  134. jack_int_t fTable[SIZE][SIZE];
  135. public:
  136. JackFixedMatrix()
  137. {}
  138. virtual ~JackFixedMatrix()
  139. {}
  140. void Init(jack_int_t index)
  141. {
  142. for (int i = 0; i < SIZE; i++) {
  143. fTable[index][i] = 0;
  144. fTable[i][index] = 0;
  145. }
  146. }
  147. const jack_int_t* GetItems(jack_int_t index) const
  148. {
  149. return fTable[index];
  150. }
  151. jack_int_t IncItem(jack_int_t index1, jack_int_t index2)
  152. {
  153. fTable[index1][index2]++;
  154. return fTable[index1][index2];
  155. }
  156. jack_int_t DecItem(jack_int_t index1, jack_int_t index2)
  157. {
  158. fTable[index1][index2]--;
  159. return fTable[index1][index2];
  160. }
  161. jack_int_t GetItemCount(jack_int_t index1, jack_int_t index2) const
  162. {
  163. return fTable[index1][index2];
  164. }
  165. /*!
  166. \brief Get the output indexes of a given index.
  167. */
  168. void GetOutputTable(jack_int_t index, jack_int_t* output) const
  169. {
  170. int i, j;
  171. for (i = 0; i < SIZE; i++)
  172. output[i] = EMPTY;
  173. for (i = 0, j = 0; i < SIZE; i++) {
  174. if (fTable[index][i] > 0) {
  175. output[j] = i;
  176. j++;
  177. }
  178. }
  179. }
  180. bool IsInsideTable(jack_int_t index, jack_int_t* output) const
  181. {
  182. for (int i = 0; i < SIZE && output[i] != EMPTY; i++) {
  183. if (output[i] == index)
  184. return true;
  185. }
  186. return false;
  187. }
  188. };
  189. /*!
  190. \brief Utility class.
  191. */
  192. template <int SIZE>
  193. class JackLoopFeedback
  194. {
  195. private:
  196. int fTable[SIZE][3];
  197. /*!
  198. \brief Add a feedback connection between 2 refnum.
  199. */
  200. bool AddConnectionAux(int ref1, int ref2)
  201. {
  202. for (int i = 0; i < SIZE; i++) {
  203. if (fTable[i][0] == EMPTY) {
  204. fTable[i][0] = ref1;
  205. fTable[i][1] = ref2;
  206. fTable[i][2] = 1;
  207. jack_log("JackLoopFeedback::AddConnectionAux ref1 = %ld ref2 = %ld", ref1, ref2);
  208. return true;
  209. }
  210. }
  211. jack_error("Feedback table is full !!\n");
  212. return false;
  213. }
  214. /*!
  215. \brief Remove a feedback connection between 2 refnum.
  216. */
  217. bool RemoveConnectionAux(int ref1, int ref2)
  218. {
  219. for (int i = 0; i < SIZE; i++) {
  220. if (fTable[i][0] == ref1 && fTable[i][1] == ref2) {
  221. fTable[i][0] = EMPTY;
  222. fTable[i][1] = EMPTY;
  223. fTable[i][2] = 0;
  224. jack_log("JackLoopFeedback::RemoveConnectionAux ref1 = %ld ref2 = %ld", ref1, ref2);
  225. return true;
  226. }
  227. }
  228. jack_error("Feedback connection not found\n");
  229. return false;
  230. }
  231. int IncConnection(int index)
  232. {
  233. fTable[index][2]++;
  234. return fTable[index][2];
  235. }
  236. int DecConnection(int index)
  237. {
  238. fTable[index][2]--;
  239. return fTable[index][2];
  240. }
  241. public:
  242. JackLoopFeedback()
  243. {
  244. Init();
  245. }
  246. virtual ~JackLoopFeedback()
  247. {}
  248. void Init()
  249. {
  250. for (int i = 0; i < SIZE; i++) {
  251. fTable[i][0] = EMPTY;
  252. fTable[i][1] = EMPTY;
  253. fTable[i][2] = 0;
  254. }
  255. }
  256. bool IncConnection(int ref1, int ref2)
  257. {
  258. int index = GetConnectionIndex(ref1, ref2);
  259. if (index >= 0) { // Feedback connection is already added, increment counter
  260. IncConnection(index);
  261. return true;
  262. } else {
  263. return AddConnectionAux(ref1, ref2); // Add the feedback connection
  264. }
  265. }
  266. bool DecConnection(int ref1, int ref2)
  267. {
  268. int index = GetConnectionIndex(ref1, ref2);
  269. if (index >= 0) {
  270. jack_log("JackLoopFeedback::DecConnection ref1 = %ld ref2 = %ld index = %ld", ref1, ref2, index);
  271. return (DecConnection(index) == 0) ? RemoveConnectionAux(ref1, ref2) : true;
  272. } else {
  273. return false;
  274. }
  275. }
  276. /*!
  277. \brief Test if a connection between 2 refnum is a feedback connection.
  278. */
  279. int GetConnectionIndex(int ref1, int ref2) const
  280. {
  281. for (int i = 0; i < SIZE; i++) {
  282. if (fTable[i][0] == ref1 && fTable[i][1] == ref2)
  283. return i;
  284. }
  285. return -1;
  286. }
  287. };
  288. /*!
  289. \brief For client timing measurements.
  290. */
  291. struct JackClientTiming
  292. {
  293. jack_time_t fSignaledAt;
  294. jack_time_t fAwakeAt;
  295. jack_time_t fFinishedAt;
  296. jack_client_state_t fStatus;
  297. JackClientTiming(): fSignaledAt(0), fAwakeAt(0), fFinishedAt(0), fStatus(NotTriggered)
  298. {}
  299. ~JackClientTiming()
  300. {}
  301. };
  302. /*!
  303. \brief Connection manager.
  304. <UL>
  305. <LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port.
  306. <LI>The <B>fConnectionCount</B> array contains the number of connected ports to a given port.
  307. <LI>The <B>fInputPort</B> array contains the list (array line) of input connected ports for a given client.
  308. <LI>The <B>fOutputPort</B> array contains the list (array line) of ouput connected ports for a given client.
  309. <LI>The <B>fConnectionRef</B> array contains the number of ports connected between two clients.
  310. <LI>The <B>fInputRef</B> array contains the number of input clients connected to a given client.
  311. <LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose.
  312. </UL>
  313. */
  314. class JackConnectionManager
  315. {
  316. private:
  317. JackFixedArray<CONNECTION_NUM> fConnection[PORT_NUM]; /*! Connection matrix: list of connected ports for a given port: needed to compute Mix buffer */
  318. JackFixedArray1<PORT_NUM_FOR_CLIENT> fInputPort[CLIENT_NUM]; /*! Table of input port per refnum : to find a refnum for a given port */
  319. JackFixedArray<PORT_NUM_FOR_CLIENT> fOutputPort[CLIENT_NUM]; /*! Table of output port per refnum : to find a refnum for a given port */
  320. JackFixedMatrix<CLIENT_NUM> fConnectionRef; /*! Table of port connections by (refnum , refnum) */
  321. JackActivationCount fInputCounter[CLIENT_NUM]; /*! Activation counter per refnum */
  322. JackLoopFeedback<CONNECTION_NUM> fLoopFeedback; /*! Loop feedback connections */
  323. bool IsLoopPathAux(int ref1, int ref2) const;
  324. public:
  325. JackConnectionManager();
  326. ~JackConnectionManager();
  327. // Connections management
  328. int Connect(jack_port_id_t port_src, jack_port_id_t port_dst);
  329. int Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst);
  330. bool IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const;
  331. jack_int_t Connections(jack_port_id_t port_index) const;
  332. jack_port_id_t GetPort(jack_port_id_t port_index, int connection) const;
  333. const jack_int_t* GetConnections(jack_port_id_t port_index) const;
  334. bool IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
  335. bool DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
  336. bool IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const;
  337. bool IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const;
  338. void IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
  339. void DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
  340. // Ports management
  341. int AddInputPort(int refnum, jack_port_id_t port_index);
  342. int AddOutputPort(int refnum, jack_port_id_t port_index);
  343. int RemoveInputPort(int refnum, jack_port_id_t port_index);
  344. int RemoveOutputPort(int refnum, jack_port_id_t port_index);
  345. const jack_int_t* GetInputPorts(int refnum);
  346. const jack_int_t* GetOutputPorts(int refnum);
  347. // Client management
  348. void InitRefNum(int refnum);
  349. int GetInputRefNum(jack_port_id_t port_index) const;
  350. int GetOutputRefNum(jack_port_id_t port_index) const;
  351. // Connect/Disconnect 2 refnum "directly"
  352. bool IsDirectConnection(int ref1, int ref2) const;
  353. void DirectConnect(int ref1, int ref2);
  354. void DirectDisconnect(int ref1, int ref2);
  355. int GetActivation(int refnum) const;
  356. // Graph
  357. void ResetGraph(JackClientTiming* timing);
  358. int ResumeRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing);
  359. int SuspendRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing, long time_out_usec);
  360. };
  361. } // end of namespace
  362. #endif