The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

454 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  24. #if JUCE_USE_CDBURNER
  25. #import <Cocoa/Cocoa.h>
  26. #import <DiscRecording/DiscRecording.h>
  27. BEGIN_JUCE_NAMESPACE
  28. #include "../../../src/juce_appframework/audio/audio_file_formats/juce_AudioCDBurner.h"
  29. #include "../../../src/juce_appframework/audio/audio_sources/juce_AudioSource.h"
  30. #include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
  31. #include "../../../src/juce_core/threads/juce_Thread.h"
  32. END_JUCE_NAMESPACE
  33. //==============================================================================
  34. @interface OpenDiskDevice : NSObject
  35. {
  36. DRDevice* device;
  37. NSMutableArray* tracks;
  38. }
  39. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device;
  40. - (void) dealloc;
  41. - (bool) isDiskPresent;
  42. - (int) getNumAvailableAudioBlocks;
  43. - (void) addSourceTrack: (juce::AudioSource*) source numSamples: (int) numSamples_;
  44. - (void) burn: (juce::AudioCDBurner::BurnProgressListener*) listener errorString: (juce::String*) error
  45. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting;
  46. @end
  47. //==============================================================================
  48. @interface AudioTrackProducer : NSObject
  49. {
  50. juce::AudioSource* source;
  51. int readPosition, lengthInFrames;
  52. }
  53. - (AudioTrackProducer*) init: (int) lengthInFrames;
  54. - (AudioTrackProducer*) initWithAudioSource: (juce::AudioSource*) source numSamples: (int) lengthInSamples;
  55. - (void) dealloc;
  56. - (void) setupTrackProperties: (DRTrack*) track;
  57. - (void) cleanupTrackAfterBurn: (DRTrack*) track;
  58. - (BOOL) cleanupTrackAfterVerification:(DRTrack*)track;
  59. - (uint64_t) estimateLengthOfTrack:(DRTrack*)track;
  60. - (BOOL) prepareTrack:(DRTrack*)track forBurn:(DRBurn*)burn
  61. toMedia:(NSDictionary*)mediaInfo;
  62. - (BOOL) prepareTrackForVerification:(DRTrack*)track;
  63. - (uint32_t) produceDataForTrack:(DRTrack*)track intoBuffer:(char*)buffer
  64. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  65. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  66. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  67. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  68. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  69. ioFlags:(uint32_t*)flags;
  70. - (BOOL) verifyDataForTrack:(DRTrack*)track inBuffer:(const char*)buffer
  71. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  72. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  73. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  74. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  75. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  76. ioFlags:(uint32_t*)flags;
  77. @end
  78. //==============================================================================
  79. @implementation OpenDiskDevice
  80. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device_
  81. {
  82. [super init];
  83. device = device_;
  84. tracks = [[NSMutableArray alloc] init];
  85. return self;
  86. }
  87. - (void) dealloc
  88. {
  89. [tracks release];
  90. [super dealloc];
  91. }
  92. - (bool) isDiskPresent
  93. {
  94. NSLog ([[device status] description]);
  95. return [device isValid];
  96. }
  97. - (int) getNumAvailableAudioBlocks
  98. {
  99. NSLog ([[device status] description]);
  100. return [[[[device status] objectForKey: DRDeviceMediaInfoKey]
  101. objectForKey: DRDeviceMediaBlocksFreeKey] intValue];
  102. }
  103. - (void) addSourceTrack: (juce::AudioSource*) source_ numSamples: (int) numSamples_
  104. {
  105. AudioTrackProducer* p = [[AudioTrackProducer alloc] initWithAudioSource: source_ numSamples: numSamples_];
  106. DRTrack* t = [[DRTrack alloc] initWithProducer: p];
  107. [p setupTrackProperties: t];
  108. [tracks addObject: t];
  109. [t release];
  110. [p release];
  111. }
  112. - (void) burn: (juce::AudioCDBurner::BurnProgressListener*) listener errorString: (juce::String*) error
  113. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting
  114. {
  115. DRBurn* burn = [DRBurn burnForDevice: device];
  116. if (! [device acquireExclusiveAccess])
  117. {
  118. *error = "Couldn't open or write to the CD device";
  119. return;
  120. }
  121. [device acquireMediaReservation];
  122. NSMutableDictionary* d = [[burn properties] mutableCopy];
  123. [d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
  124. [d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
  125. [burn setProperties: d];
  126. [d release];
  127. [burn writeLayout: tracks];
  128. for (;;)
  129. {
  130. juce::Thread::sleep (300);
  131. float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
  132. if (listener != 0 && listener->audioCDBurnProgress (progress))
  133. {
  134. [burn abort];
  135. *error = "User cancelled the write operation";
  136. break;
  137. }
  138. if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
  139. {
  140. *error = "Write operation failed";
  141. break;
  142. }
  143. else if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
  144. {
  145. if (shouldEject)
  146. [device openTray];
  147. break;
  148. }
  149. NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
  150. objectForKey: DRErrorStatusErrorStringKey];
  151. if ([err length] > 0)
  152. {
  153. *error = juce::String::fromUTF8 ((juce::uint8*) [err UTF8String]);
  154. break;
  155. }
  156. }
  157. [device releaseMediaReservation];
  158. [device releaseExclusiveAccess];
  159. }
  160. @end
  161. //==============================================================================
  162. @implementation AudioTrackProducer
  163. - (AudioTrackProducer*) init: (int) lengthInFrames_
  164. {
  165. lengthInFrames = lengthInFrames_;
  166. readPosition = 0;
  167. return self;
  168. }
  169. - (void) setupTrackProperties: (DRTrack*) track
  170. {
  171. NSMutableDictionary* p = [[track properties] mutableCopy];
  172. [p setObject: [DRMSF msfWithFrames: lengthInFrames] forKey: DRTrackLengthKey];
  173. [p setObject: [NSNumber numberWithUnsignedShort: 2048] forKey: DRBlockSizeKey];
  174. [p setObject: [NSNumber numberWithInt: 16] forKey: DRDataFormKey];
  175. [p setObject: [NSNumber numberWithInt: 8] forKey: DRBlockTypeKey];
  176. [p setObject: [NSNumber numberWithInt: 4] forKey: DRTrackModeKey];
  177. [p setObject: [NSNumber numberWithInt: 0] forKey: DRSessionFormatKey];
  178. [track setProperties: p];
  179. [p release];
  180. }
  181. - (AudioTrackProducer*) initWithAudioSource: (juce::AudioSource*) source_ numSamples: (int) lengthInSamples
  182. {
  183. AudioTrackProducer* s = [self init: lengthInSamples / (44100 / 75)];
  184. if (s != nil)
  185. s->source = source_;
  186. return s;
  187. }
  188. - (void) dealloc
  189. {
  190. if (source != 0)
  191. {
  192. source->releaseResources();
  193. delete source;
  194. }
  195. [super dealloc];
  196. }
  197. - (void) cleanupTrackAfterBurn: (DRTrack*) track
  198. {
  199. }
  200. - (BOOL) cleanupTrackAfterVerification:(DRTrack*)track
  201. {
  202. return true;
  203. }
  204. - (uint64_t) estimateLengthOfTrack:(DRTrack*)track
  205. {
  206. return lengthInFrames;
  207. }
  208. - (BOOL) prepareTrack:(DRTrack*)track forBurn:(DRBurn*)burn
  209. toMedia:(NSDictionary*)mediaInfo
  210. {
  211. if (source != 0)
  212. source->prepareToPlay (44100 / 75, 44100);
  213. readPosition = 0;
  214. return true;
  215. }
  216. - (BOOL) prepareTrackForVerification:(DRTrack*)track
  217. {
  218. if (source != 0)
  219. source->prepareToPlay (44100 / 75, 44100);
  220. return true;
  221. }
  222. - (uint32_t) produceDataForTrack:(DRTrack*)track intoBuffer:(char*)buffer
  223. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  224. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags
  225. {
  226. if (source != 0)
  227. {
  228. const int numSamples = juce::jmin (bufferLength / 4, (lengthInFrames * (44100 / 75)) - readPosition);
  229. if (numSamples > 0)
  230. {
  231. juce::AudioSampleBuffer tempBuffer (2, numSamples);
  232. juce::AudioSourceChannelInfo info;
  233. info.buffer = &tempBuffer;
  234. info.startSample = 0;
  235. info.numSamples = numSamples;
  236. source->getNextAudioBlock (info);
  237. juce::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (0),
  238. buffer, numSamples, 4);
  239. juce::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (1),
  240. buffer + 2, numSamples, 4);
  241. readPosition += numSamples;
  242. }
  243. return numSamples * 4;
  244. }
  245. return 0;
  246. }
  247. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  248. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  249. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  250. ioFlags:(uint32_t*)flags
  251. {
  252. zeromem (buffer, bufferLength);
  253. return bufferLength;
  254. }
  255. - (BOOL) verifyDataForTrack:(DRTrack*)track inBuffer:(const char*)buffer
  256. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  257. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags
  258. {
  259. return true;
  260. }
  261. @end
  262. BEGIN_JUCE_NAMESPACE
  263. //==============================================================================
  264. AudioCDBurner::AudioCDBurner (const int deviceIndex)
  265. : internal (0)
  266. {
  267. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  268. OpenDiskDevice* dev = [[OpenDiskDevice alloc] initWithDevice: [[DRDevice devices] objectAtIndex: deviceIndex]];
  269. internal = (void*) dev;
  270. [pool release];
  271. }
  272. AudioCDBurner::~AudioCDBurner()
  273. {
  274. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  275. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  276. if (dev != 0)
  277. [dev release];
  278. [pool release];
  279. }
  280. AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
  281. {
  282. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  283. AudioCDBurner* b = new AudioCDBurner (deviceIndex);
  284. if (b->internal == 0)
  285. deleteAndZero (b);
  286. [pool release];
  287. return b;
  288. }
  289. static NSArray* findDiskBurnerDevices()
  290. {
  291. NSMutableArray* results = [NSMutableArray array];
  292. NSArray* devs = [DRDevice devices];
  293. if (devs != 0)
  294. {
  295. int num = [devs count];
  296. int i;
  297. for (i = 0; i < num; ++i)
  298. {
  299. NSDictionary* dic = [[devs objectAtIndex: i] info];
  300. NSString* name = [dic valueForKey: DRDeviceProductNameKey];
  301. if (name != nil)
  302. [results addObject: name];
  303. }
  304. }
  305. return results;
  306. }
  307. const StringArray AudioCDBurner::findAvailableDevices()
  308. {
  309. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  310. NSArray* names = findDiskBurnerDevices();
  311. StringArray s;
  312. for (int i = 0; i < [names count]; ++i)
  313. s.add (String::fromUTF8 ((juce::uint8*) [[names objectAtIndex: i] UTF8String]));
  314. [pool release];
  315. return s;
  316. }
  317. bool AudioCDBurner::isDiskPresent() const
  318. {
  319. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  320. return dev != 0 && [dev isDiskPresent];
  321. }
  322. int AudioCDBurner::getNumAvailableAudioBlocks() const
  323. {
  324. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  325. return [dev getNumAvailableAudioBlocks];
  326. }
  327. bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamps)
  328. {
  329. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  330. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  331. if (dev != 0)
  332. {
  333. [dev addSourceTrack: source numSamples: numSamps];
  334. [pool release];
  335. return true;
  336. }
  337. [pool release];
  338. return false;
  339. }
  340. const String AudioCDBurner::burn (juce::AudioCDBurner::BurnProgressListener* listener,
  341. const bool peformFakeBurnForTesting,
  342. const bool ejectDiscAfterwards)
  343. {
  344. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  345. juce::String error ("Couldn't open or write to the CD device");
  346. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  347. if (dev != 0)
  348. {
  349. error = juce::String::empty;
  350. [dev burn: listener
  351. errorString: &error
  352. ejectAfterwards: ejectDiscAfterwards
  353. isFake: peformFakeBurnForTesting];
  354. }
  355. [pool release];
  356. return error;
  357. }
  358. END_JUCE_NAMESPACE
  359. #endif