int jack_card_read(JackCard *obj,char *buf,int size) { size_t bytes, can_read, i; int error; float norm, value; g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1); if (jack_init(obj) != 0) return -1; size /= 2; can_read = MIN(size, obj->read.frames); // can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer)); can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t); obj->read.can_process = FALSE; bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read); obj->read.can_process = TRUE; obj->read.data.input_frames = bytes / sizeof(sample_t); can_read = MIN(size, obj->read.frames); obj->read.data.output_frames = can_read; if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0) g_warning("error while samplerate conversion. error: %s", src_strerror(error)); norm = obj->read.level*obj->level*(float)0x8000; for (i=0; i < obj->read.data.output_frames_gen; i++) { value = obj->read.data.data_out[i]*norm; if (value >= 32767.0) ((short*)buf)[i] = 32767; else if (value <= -32768.0) ((short*)buf)[i] = -32768; else ((short*)buf)[i] = (short)value; } bytes = obj->read.data.output_frames_gen * 2; return bytes; }
int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate) { int channels = stereo + 1, bsize, err; obj->write.init = TRUE; if (jack_init(obj) != 0) return -1; obj->write.rate = rate; obj->sample_size = bits / 8; obj->frame_size = channels * obj->sample_size; bsize = BSIZE; obj->write.frames = bsize / 2; SND_CARD(obj)->bsize = bsize; SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED; obj->write.channels = channels; if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL) g_warning("Error while initializing the samplerate converter: %s", src_strerror(err)); obj->write.data.src_ratio = (double)obj->rate / (double)rate; obj->write.data.data_in = malloc(obj->write.frames*sizeof(float)); obj->write.data.end_of_input = 0; obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio); obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float)); if (!obj->write.buffer) obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE); obj->write.can_process = TRUE; obj->can_process = TRUE; obj->write.open = TRUE; obj->write.init = FALSE; return 0; }
int jack_card_write(JackCard *obj,char *buf,int size) { size_t bytes, can_write, i; int error; float norm; g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1); if (jack_init(obj) != 0) return -1; size /= 2; can_write = MIN(size, obj->write.frames); norm = obj->write.level*obj->level/(float)0x8000; for (i=0; i<can_write; i++) { obj->write.data.data_in[i] = (float)((short*)buf)[i]*norm; } obj->write.data.input_frames = can_write; if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0) g_warning("error while samplerate conversion. error: %s", src_strerror(error)); obj->write.can_process = FALSE; bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen); obj->write.can_process = TRUE; return bytes; }
int jack_watchdog(void) { int watchdog_state = WATCHDOG_STATE_CLIENT_ACTIVE; while (!shutdown) { #ifdef EXTRA_DEBUG if (debug) { fprintf (stderr, "JACK Watchdog loop...\n"); } #endif if (gtkui_restarting) { pthread_join (gtkui_thread_p, NULL); start_gtkui_thread (); } /* poll lash for events */ #ifndef WITHOUT_LASH lash_pollevent(); #endif /* everybody sleeps */ usleep (250000); switch (watchdog_state) { case WATCHDOG_STATE_CLIENT_ACTIVE: /* make sure the thread didn't go away */ if (client == NULL) { if (debug && !shutdown) { fprintf (stderr, "JACK Watchdog: JACK client went away! Attempting to recover.\n"); } watchdog_state = WATCHDOG_STATE_NO_CLIENT; usleep (250000); } else { #ifdef JOIN_JACK_CLIENT_THREAD /* if there's a jack client thread, wait for it to die */ if (debug) { fprintf (stderr, "JACK Watchdog: Waiting for JACK client thread 0x%lx to exit.\n", jack_thread_p); } if (pthread_join (jack_thread_p, NULL) == 0) { if (debug) { fprintf (stderr, "JACK Watchdog: pthread_join() successful!\n"); } /* client is invalid at this point, so don't call jack_client_close() */ client = NULL; jack_thread_p = 0; jack_running = 0; watchdog_state = WATCHDOG_STATE_NO_CLIENT; usleep (250000); } else { if (debug) { fprintf (stderr, "JACK Watchdog: pthread_join() on JACK client thread 0x%lx failed!\n", jack_thread_p); } } #else if (jack_thread_p == 0) { if (debug) { fprintf (stderr, "JACK Watchdog: JACK thread went away! Attempting to recover.\n"); } client = NULL; jack_running = 0; watchdog_state = WATCHDOG_STATE_NO_CLIENT; usleep (250000); } #endif } usleep (250000); break; case WATCHDOG_STATE_NO_CLIENT: /* open a new client */ if (jack_init () == 0) { if (debug) { fprintf (stderr, "JACK Watchdog: Initialized JACK client.\n"); } jack_thread_p = 0; jack_running = 0; watchdog_state = WATCHDOG_STATE_CLIENT_INIT; } else { if (debug) { fprintf (stderr, "JACK Watchdog: Waiting for JACK server...\n"); } } usleep (250000); break; case WATCHDOG_STATE_CLIENT_INIT: /* start client */ if (jack_start () == 0) { if (debug) { fprintf (stderr, "JACK Watchdog: Started JACK with client thread 0x%lx\n", jack_thread_p); } jack_running = 1; watchdog_state = WATCHDOG_STATE_CLIENT_ACTIVE; } else { if (debug) { fprintf (stderr, "JACK Watchdog: Unable to start JACK client.\n"); } jack_thread_p = 0; if (client != NULL) { /* no thread to wait for unless jack client actually starts */ jack_client_close (client); client = NULL; } watchdog_state = WATCHDOG_STATE_NO_CLIENT; } usleep (250000); break; } } usleep (250000); if ((client != NULL) && (jack_thread_p != 0)) { jack_client_close (client); client = NULL; jack_thread_p = 0; } /* not reached */ return 0; }
int main(int argc, char *argv[]) { int rc = -1, n, priority; const char *importer, *scanner, *geo; char *endptr; size_t nctl; double speed; struct timecode_def *timecode; bool protect, use_mlock, phono; struct controller ctl[2]; struct rt rt; struct library library; #if defined WITH_OSS || WITH_ALSA int rate; #endif #ifdef WITH_OSS int oss_buffers, oss_fragment; #endif #ifdef WITH_ALSA int alsa_buffer; #endif fprintf(stderr, "%s\n\n" NOTICE "\n\n", banner); if (thread_global_init() == -1) return -1; if (rig_init() == -1) return -1; rt_init(&rt); library_init(&library); ndeck = 0; geo = ""; nctl = 0; priority = DEFAULT_PRIORITY; importer = DEFAULT_IMPORTER; scanner = DEFAULT_SCANNER; timecode = NULL; speed = 1.0; protect = false; phono = false; use_mlock = false; #if defined WITH_OSS || WITH_ALSA rate = DEFAULT_RATE; #endif #ifdef WITH_ALSA alsa_buffer = DEFAULT_ALSA_BUFFER; #endif #ifdef WITH_OSS oss_fragment = DEFAULT_OSS_FRAGMENT; oss_buffers = DEFAULT_OSS_BUFFERS; #endif /* Skip over command name */ argv++; argc--; while (argc > 0) { if (!strcmp(argv[0], "-h")) { usage(stdout); return 0; #ifdef WITH_OSS } else if (!strcmp(argv[0], "-f")) { /* Set fragment size for subsequent devices */ if (argc < 2) { fprintf(stderr, "-f requires an integer argument.\n"); return -1; } oss_fragment = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-f requires an integer argument.\n"); return -1; } /* Fragment sizes greater than the default aren't useful * as they are dependent on DEVICE_FRAME */ if (oss_fragment < DEFAULT_OSS_FRAGMENT) { fprintf(stderr, "Fragment size must be %d or more; aborting.\n", DEFAULT_OSS_FRAGMENT); return -1; } argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-b")) { /* Set number of buffers for subsequent devices */ if (argc < 2) { fprintf(stderr, "-b requires an integer argument.\n"); return -1; } oss_buffers = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-b requires an integer argument.\n"); return -1; } argv += 2; argc -= 2; #endif #if defined WITH_OSS || WITH_ALSA } else if (!strcmp(argv[0], "-r")) { /* Set sample rate for subsequence devices */ if (argc < 2) { fprintf(stderr, "-r requires an integer argument.\n"); return -1; } rate = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-r requires an integer argument.\n"); return -1; } argv += 2; argc -= 2; #endif #ifdef WITH_ALSA } else if (!strcmp(argv[0], "-m")) { /* Set size of ALSA buffer for subsequence devices */ if (argc < 2) { fprintf(stderr, "-m requires an integer argument.\n"); return -1; } alsa_buffer = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-m requires an integer argument.\n"); return -1; } argv += 2; argc -= 2; #endif } else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "-a") || !strcmp(argv[0], "-j")) { int r; unsigned int sample_rate; struct deck *ld; struct device *device; struct timecoder *timecoder; /* Create a deck */ if (argc < 2) { fprintf(stderr, "-%c requires a device name as an argument.\n", argv[0][1]); return -1; } if (ndeck == ARRAY_SIZE(deck)) { fprintf(stderr, "Too many decks; aborting.\n"); return -1; } fprintf(stderr, "Initialising deck %zd (%s)...\n", ndeck, argv[1]); ld = &deck[ndeck]; device = &ld->device; timecoder = &ld->timecoder; ld->importer = importer; ld->protect = protect; /* Work out which device type we are using, and initialise * an appropriate device. */ switch(argv[0][1]) { #ifdef WITH_OSS case 'd': r = oss_init(device, argv[1], rate, oss_buffers, oss_fragment); break; #endif #ifdef WITH_ALSA case 'a': r = alsa_init(device, argv[1], rate, alsa_buffer); break; #endif #ifdef WITH_JACK case 'j': r = jack_init(device, argv[1]); break; #endif default: fprintf(stderr, "Device type is not supported by this " "distribution of xwax.\n"); return -1; } if (r == -1) return -1; sample_rate = device_sample_rate(device); /* Default timecode decoder where none is specified */ if (timecode == NULL) { timecode = timecoder_find_definition(DEFAULT_TIMECODE); assert(timecode != NULL); } timecoder_init(timecoder, timecode, speed, sample_rate, phono); /* Connect up the elements to make an operational deck */ r = deck_init(ld, &rt, ndeck); if (r == -1) return -1; /* Connect this deck to available controllers */ for (n = 0; n < nctl; n++) controller_add_deck(&ctl[n], &deck[ndeck]); /* Connect this deck to OSC server */ osc_add_deck(); ndeck++; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-t")) { /* Set the timecode definition to use */ if (argc < 2) { fprintf(stderr, "-t requires a name as an argument.\n"); return -1; } timecode = timecoder_find_definition(argv[1]); if (timecode == NULL) { fprintf(stderr, "Timecode '%s' is not known.\n", argv[1]); return -1; } argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-33")) { speed = 1.0; argv++; argc--; } else if (!strcmp(argv[0], "-45")) { speed = 1.35; argv++; argc--; } else if (!strcmp(argv[0], "-c")) { protect = true; argv++; argc--; } else if (!strcmp(argv[0], "-u")) { protect = false; argv++; argc--; } else if (!strcmp(argv[0], "--line")) { phono = false; argv++; argc--; } else if (!strcmp(argv[0], "--phono")) { phono = true; argv++; argc--; } else if (!strcmp(argv[0], "-k")) { use_mlock = true; track_use_mlock(); argv++; argc--; } else if (!strcmp(argv[0], "-q")) { if (argc < 2) { fprintf(stderr, "-q requires an integer argument.\n"); return -1; } priority = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-q requires an integer argument.\n"); return -1; } if (priority < 0) { fprintf(stderr, "Priority (%d) must be zero or positive.\n", priority); return -1; } argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-g")) { if (argc < 2) { fprintf(stderr, "-g requires an argument.\n"); return -1; } geo = argv[1]; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-i")) { /* Importer script for subsequent decks */ if (argc < 2) { fprintf(stderr, "-i requires an executable path " "as an argument.\n"); return -1; } importer = argv[1]; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-s")) { /* Scan script for subsequent libraries */ if (argc < 2) { fprintf(stderr, "-s requires an executable path " "as an argument.\n"); return -1; } scanner = argv[1]; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-l")) { /* Load in a music library */ if (argc < 2) { fprintf(stderr, "-%c requires a pathname as an argument.\n", argv[0][1]); return -1; } if (library_import(&library, scanner, argv[1]) == -1) return -1; argv += 2; argc -= 2; #ifdef WITH_ALSA } else if (!strcmp(argv[0], "--dicer")) { struct controller *c; if (nctl == sizeof ctl) { fprintf(stderr, "Too many controllers; aborting.\n"); return -1; } c = &ctl[nctl]; if (argc < 2) { fprintf(stderr, "Dicer requires an ALSA device name.\n"); return -1; } if (dicer_init(c, &rt, argv[1]) == -1) return -1; nctl++; argv += 2; argc -= 2; #endif } else { fprintf(stderr, "'%s' argument is unknown; try -h.\n", argv[0]); return -1; } } #ifdef WITH_ALSA alsa_clear_config_cache(); #endif if (ndeck == 0) { fprintf(stderr, "You need to give at least one audio device to use " "as a deck; try -h.\n"); return -1; } rc = EXIT_FAILURE; /* until clean exit */ if (osc_start((struct deck *)&deck, &library) == -1) return -1; osc_start_updater_thread(); /* Order is important: launch realtime thread first, then mlock. * Don't mlock the interface, use sparingly for audio threads */ if (rt_start(&rt, priority) == -1) return -1; if (use_mlock && mlockall(MCL_CURRENT) == -1) { perror("mlockall"); goto out_rt; } if (interface_start(&library, geo) == -1) goto out_rt; if (rig_main() == -1) goto out_interface; rc = EXIT_SUCCESS; fprintf(stderr, "Exiting cleanly...\n"); out_interface: interface_stop(); out_rt: rt_stop(&rt); for (n = 0; n < ndeck; n++) deck_clear(&deck[n]); for (n = 0; n < nctl; n++) controller_clear(&ctl[n]); timecoder_free_lookup(); library_clear(&library); rt_clear(&rt); rig_clear(); osc_stop(); thread_global_clear(); if (rc == EXIT_SUCCESS) fprintf(stderr, "Done.\n"); return rc; }
SndCard * jack_card_new(jack_client_t *client) { JackCard * obj; SndCard *base; obj= g_new0(JackCard,1); if (!client) return NULL; obj->client = client; obj->jack_running = TRUE; obj->jack_active = FALSE; obj->can_process = FALSE; obj->clear = TRUE; obj->write.can_process = FALSE; obj->write.open = FALSE; obj->write.init = TRUE; obj->write.port = NULL; obj->write.phys_ports = NULL; obj->write.buffer = NULL; obj->read.can_process = FALSE; obj->read.open = FALSE; obj->read.init = TRUE; obj->read.port = NULL; obj->read.phys_ports = NULL; obj->read.buffer = NULL; /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, obj); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, obj); jack_set_sample_rate_callback (client, samplerate, obj); obj->rate = jack_get_sample_rate (client); obj->buffer_size = jack_get_buffer_size(obj->client); jack_init(obj); base= SND_CARD(obj); snd_card_init(base); #ifdef HAVE_GLIB base->card_name=g_strdup_printf("JACK client"); #else base->card_name=malloc(100); snprintf(base->card_name, 100, "JACK client"); #endif base->_probe=(SndCardOpenFunc)jack_card_probe; base->_open_r=(SndCardOpenFunc)jack_card_open_r; base->_open_w=(SndCardOpenFunc)jack_card_open_w; base->_can_read=(SndCardPollFunc)jack_card_can_read; base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode; base->_read=(SndCardIOFunc)jack_card_read; base->_write=(SndCardIOFunc)jack_card_write; base->_close_r=(SndCardCloseFunc)jack_card_close_r; base->_close_w=(SndCardCloseFunc)jack_card_close_w; base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source; base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level; base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level; base->_destroy=(SndCardDestroyFunc)jack_card_destroy; base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter; base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter; obj->read.buffer=NULL; obj->write.buffer=NULL; obj->buffer_size = 0; obj->level = 1.0; obj->write.level = 1.0; obj->read.level = 1.0; return base; }
int jack_card_probe(JackCard *obj,int bits,int stereo,int rate) { if (obj->jack_running) return BSIZE; else if (jack_init(obj) == 0) return BSIZE; else return -1; }