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.

449 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 "juce_mac_NativeHeaders.h"
  24. #if JUCE_USE_CDBURNER
  25. #import <DiscRecording/DiscRecording.h>
  26. BEGIN_JUCE_NAMESPACE
  27. #include "../../../src/juce_appframework/audio/audio_file_formats/juce_AudioCDBurner.h"
  28. #include "../../../src/juce_appframework/audio/audio_sources/juce_AudioSource.h"
  29. #include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
  30. #include "../../../src/juce_core/threads/juce_Thread.h"
  31. END_JUCE_NAMESPACE
  32. //==============================================================================
  33. @interface OpenDiskDevice : NSObject
  34. {
  35. DRDevice* device;
  36. NSMutableArray* tracks;
  37. }
  38. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device;
  39. - (void) dealloc;
  40. - (bool) isDiskPresent;
  41. - (int) getNumAvailableAudioBlocks;
  42. - (void) addSourceTrack: (JUCE_NAMESPACE::AudioSource*) source numSamples: (int) numSamples_;
  43. - (void) burn: (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener*) listener errorString: (JUCE_NAMESPACE::String*) error
  44. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting;
  45. @end
  46. //==============================================================================
  47. @interface AudioTrackProducer : NSObject
  48. {
  49. JUCE_NAMESPACE::AudioSource* source;
  50. int readPosition, lengthInFrames;
  51. }
  52. - (AudioTrackProducer*) init: (int) lengthInFrames;
  53. - (AudioTrackProducer*) initWithAudioSource: (JUCE_NAMESPACE::AudioSource*) source numSamples: (int) lengthInSamples;
  54. - (void) dealloc;
  55. - (void) setupTrackProperties: (DRTrack*) track;
  56. - (void) cleanupTrackAfterBurn: (DRTrack*) track;
  57. - (BOOL) cleanupTrackAfterVerification:(DRTrack*)track;
  58. - (uint64_t) estimateLengthOfTrack:(DRTrack*)track;
  59. - (BOOL) prepareTrack:(DRTrack*)track forBurn:(DRBurn*)burn
  60. toMedia:(NSDictionary*)mediaInfo;
  61. - (BOOL) prepareTrackForVerification:(DRTrack*)track;
  62. - (uint32_t) produceDataForTrack:(DRTrack*)track intoBuffer:(char*)buffer
  63. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  64. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  65. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  66. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  67. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  68. ioFlags:(uint32_t*)flags;
  69. - (BOOL) verifyDataForTrack:(DRTrack*)track inBuffer:(const char*)buffer
  70. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  71. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  72. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  73. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  74. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  75. ioFlags:(uint32_t*)flags;
  76. @end
  77. //==============================================================================
  78. @implementation OpenDiskDevice
  79. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device_
  80. {
  81. [super init];
  82. device = device_;
  83. tracks = [[NSMutableArray alloc] init];
  84. return self;
  85. }
  86. - (void) dealloc
  87. {
  88. [tracks release];
  89. [super dealloc];
  90. }
  91. - (bool) isDiskPresent
  92. {
  93. return [device isValid]
  94. && [[[device status] objectForKey: DRDeviceMediaStateKey]
  95. isEqualTo: DRDeviceMediaStateMediaPresent];
  96. }
  97. - (int) getNumAvailableAudioBlocks
  98. {
  99. return [[[[device status] objectForKey: DRDeviceMediaInfoKey]
  100. objectForKey: DRDeviceMediaBlocksFreeKey] intValue];
  101. }
  102. - (void) addSourceTrack: (JUCE_NAMESPACE::AudioSource*) source_ numSamples: (int) numSamples_
  103. {
  104. AudioTrackProducer* p = [[AudioTrackProducer alloc] initWithAudioSource: source_ numSamples: numSamples_];
  105. DRTrack* t = [[DRTrack alloc] initWithProducer: p];
  106. [p setupTrackProperties: t];
  107. [tracks addObject: t];
  108. [t release];
  109. [p release];
  110. }
  111. - (void) burn: (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener*) listener errorString: (JUCE_NAMESPACE::String*) error
  112. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting
  113. {
  114. DRBurn* burn = [DRBurn burnForDevice: device];
  115. if (! [device acquireExclusiveAccess])
  116. {
  117. *error = "Couldn't open or write to the CD device";
  118. return;
  119. }
  120. [device acquireMediaReservation];
  121. NSMutableDictionary* d = [[burn properties] mutableCopy];
  122. [d autorelease];
  123. [d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
  124. [d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
  125. [d setObject: (shouldEject ? DRBurnCompletionActionEject : DRBurnCompletionActionMount)
  126. forKey: DRBurnCompletionActionKey];
  127. [burn setProperties: d];
  128. [burn writeLayout: tracks];
  129. for (;;)
  130. {
  131. JUCE_NAMESPACE::Thread::sleep (300);
  132. float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
  133. NSLog ([[burn status] description]);
  134. if (listener != 0 && listener->audioCDBurnProgress (progress))
  135. {
  136. [burn abort];
  137. *error = "User cancelled the write operation";
  138. break;
  139. }
  140. if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
  141. {
  142. *error = "Write operation failed";
  143. break;
  144. }
  145. else if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
  146. {
  147. break;
  148. }
  149. NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
  150. objectForKey: DRErrorStatusErrorStringKey];
  151. if ([err length] > 0)
  152. {
  153. *error = JUCE_NAMESPACE::String::fromUTF8 ((JUCE_NAMESPACE::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:2352] forKey: DRBlockSizeKey];
  174. [p setObject:[NSNumber numberWithInt:0] forKey: DRDataFormKey];
  175. [p setObject:[NSNumber numberWithInt:0] forKey: DRBlockTypeKey];
  176. [p setObject:[NSNumber numberWithInt:0] forKey: DRTrackModeKey];
  177. [p setObject:[NSNumber numberWithInt:0] forKey: DRSessionFormatKey];
  178. [track setProperties: p];
  179. [p release];
  180. }
  181. - (AudioTrackProducer*) initWithAudioSource: (JUCE_NAMESPACE::AudioSource*) source_ numSamples: (int) lengthInSamples
  182. {
  183. AudioTrackProducer* s = [self init: (lengthInSamples + 587) / 588];
  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_NAMESPACE::jmin (bufferLength / 4, (lengthInFrames * (44100 / 75)) - readPosition);
  229. if (numSamples > 0)
  230. {
  231. JUCE_NAMESPACE::AudioSampleBuffer tempBuffer (2, numSamples);
  232. JUCE_NAMESPACE::AudioSourceChannelInfo info;
  233. info.buffer = &tempBuffer;
  234. info.startSample = 0;
  235. info.numSamples = numSamples;
  236. source->getNextAudioBlock (info);
  237. JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (0),
  238. buffer, numSamples, 4);
  239. JUCE_NAMESPACE::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. const AutoPool pool;
  268. OpenDiskDevice* dev = [[OpenDiskDevice alloc] initWithDevice: [[DRDevice devices] objectAtIndex: deviceIndex]];
  269. internal = (void*) dev;
  270. }
  271. AudioCDBurner::~AudioCDBurner()
  272. {
  273. const AutoPool pool;
  274. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  275. if (dev != 0)
  276. [dev release];
  277. }
  278. AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
  279. {
  280. const AutoPool pool;
  281. AudioCDBurner* b = new AudioCDBurner (deviceIndex);
  282. if (b->internal == 0)
  283. deleteAndZero (b);
  284. return b;
  285. }
  286. static NSArray* findDiskBurnerDevices()
  287. {
  288. NSMutableArray* results = [NSMutableArray array];
  289. NSArray* devs = [DRDevice devices];
  290. if (devs != 0)
  291. {
  292. int num = [devs count];
  293. int i;
  294. for (i = 0; i < num; ++i)
  295. {
  296. NSDictionary* dic = [[devs objectAtIndex: i] info];
  297. NSString* name = [dic valueForKey: DRDeviceProductNameKey];
  298. if (name != nil)
  299. [results addObject: name];
  300. }
  301. }
  302. return results;
  303. }
  304. const StringArray AudioCDBurner::findAvailableDevices()
  305. {
  306. const AutoPool pool;
  307. NSArray* names = findDiskBurnerDevices();
  308. StringArray s;
  309. for (int i = 0; i < [names count]; ++i)
  310. s.add (String::fromUTF8 ((JUCE_NAMESPACE::uint8*) [[names objectAtIndex: i] UTF8String]));
  311. return s;
  312. }
  313. bool AudioCDBurner::isDiskPresent() const
  314. {
  315. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  316. return dev != 0 && [dev isDiskPresent];
  317. }
  318. int AudioCDBurner::getNumAvailableAudioBlocks() const
  319. {
  320. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  321. return [dev getNumAvailableAudioBlocks];
  322. }
  323. bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamps)
  324. {
  325. const AutoPool pool;
  326. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  327. if (dev != 0)
  328. {
  329. [dev addSourceTrack: source numSamples: numSamps];
  330. return true;
  331. }
  332. return false;
  333. }
  334. const String AudioCDBurner::burn (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener* listener,
  335. const bool ejectDiscAfterwards,
  336. const bool peformFakeBurnForTesting)
  337. {
  338. const AutoPool pool;
  339. JUCE_NAMESPACE::String error ("Couldn't open or write to the CD device");
  340. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  341. if (dev != 0)
  342. {
  343. error = JUCE_NAMESPACE::String::empty;
  344. [dev burn: listener
  345. errorString: &error
  346. ejectAfterwards: ejectDiscAfterwards
  347. isFake: peformFakeBurnForTesting];
  348. }
  349. return error;
  350. }
  351. END_JUCE_NAMESPACE
  352. #endif