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.

469 lines
13KB

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