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.

438 lines
13KB

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