Beispiel #1
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;
}
VinylControlXwax::VinylControlXwax(ConfigObject<ConfigValue>* pConfig, QString group)
        : VinylControl(pConfig, group),
          m_dVinylPositionOld(0.0),
          m_pWorkBuffer(new short[MAX_BUFFER_LEN]),
          m_workBufferSize(MAX_BUFFER_LEN),
          m_iQualPos(0),
          m_iQualFilled(0),
          m_iPosition(-1),
          m_bAtRecordEnd(false),
          m_bForceResync(false),
          m_iVCMode(mode->get()),
          m_iOldVCMode(MIXXX_VCMODE_ABSOLUTE),
          m_dOldFilePos(0.0),
          m_dOldDuration(0.0),
          m_dOldDurationInaccurate(-1.0),
          m_pPitchRing(NULL),
          m_iPitchRingSize(0),
          m_iPitchRingPos(0),
          m_iPitchRingFilled(0),
          m_dDisplayPitch(0.0),
          m_pSteadySubtle(new SteadyPitch(0.12)),
          m_pSteadyGross(new SteadyPitch(0.5)),
          m_bCDControl(false),
          m_bTrackSelectMode(false),
          m_pControlTrackSelector(NULL),
          m_pControlTrackLoader(NULL),
          m_dLastTrackSelectPos(0.0),
          m_dCurTrackSelectPos(0.0),
          m_dDriftAmt(0.0),
          m_dUiUpdateTime(-1.0) {
    // TODO(rryan): Should probably live in VinylControlManager since it's not
    // specific to a VC deck.
    signalenabled->slotSet(m_pConfig->getValueString(
        ConfigKey(VINYL_PREF_KEY, "show_signal_quality")).toInt());

    // Get the vinyl type and speed.
    QString strVinylType = m_pConfig->getValueString(
        ConfigKey(group,"vinylcontrol_vinyl_type"));
    QString strVinylSpeed = m_pConfig->getValueString(
        ConfigKey(group,"vinylcontrol_speed_type"));

    // libxwax indexes by C-strings so we pass libxwax string literals so we
    // don't have to deal with freeing the strings later
    char* timecode = NULL;


    if (strVinylType == MIXXX_VINYL_SERATOCV02VINYLSIDEA) {
        timecode = (char*)"serato_2a";
    }
    else if (strVinylType == MIXXX_VINYL_SERATOCV02VINYLSIDEB) {
        timecode = (char*)"serato_2b";
    } else if (strVinylType == MIXXX_VINYL_SERATOCD) {
        timecode = (char*)"serato_cd";
        m_bCDControl = true;
    } else if (strVinylType == MIXXX_VINYL_TRAKTORSCRATCHSIDEA) {
        timecode = (char*)"traktor_a";
    } else if (strVinylType == MIXXX_VINYL_TRAKTORSCRATCHSIDEB) {
        timecode = (char*)"traktor_b";
    } else if (strVinylType == MIXXX_VINYL_MIXVIBESDVS) {
        timecode = (char*)"mixvibes_v2";
    } else {
        qDebug() << "Unknown vinyl type, defaulting to serato_2a";
        timecode = (char*)"serato_2a";
    }

    timecode_def* tc_def = timecoder_find_definition(timecode);
    if (tc_def == NULL) {
        qDebug() << "Error finding timecode definition for " << timecode << ", defaulting to serato_2a";
        timecode = (char*)"serato_2a";
        tc_def = timecoder_find_definition(timecode);
    }

    double speed = 1.0;
    double rpm = 100.0 / 3.0;
    if (strVinylSpeed == MIXXX_VINYL_SPEED_45) {
        rpm = 45.0;
        speed = 1.35;
    }

    double latency = ControlObject::getControl(
            ConfigKey("[Master]", "latency"))->get();
    if (latency <= 0 || latency > 200) {
        qDebug() << "Failed to get sane latency, assuming 20 as a reasonable value";
        latency = 20;
    }

    int iSampleRate = m_pConfig->getValueString(
        ConfigKey("[Soundcard]","Samplerate")).toULong();

    // Set pitch ring size to 1/4 of one revolution -- a full revolution adds
    // too much stickiness to the pitch.
    m_iPitchRingSize = static_cast<int>(60000 / (rpm * latency * 4));
    m_pPitchRing = new double[m_iPitchRingSize];

    qDebug() << "Xwax Vinyl control starting with a sample rate of:" << iSampleRate;
    qDebug() << "Building timecode lookup tables for" << strVinylType << "with speed" << strVinylSpeed;

    // Initialize the timecoder structure. Use the static mutex so that we only
    // do this once across the VinylControlXwax instances.
    s_xwaxLUTMutex.lock();

    timecoder_init(&timecoder, tc_def, speed, iSampleRate, /* phono */ false);
    timecoder_monitor_init(&timecoder, MIXXX_VINYL_SCOPE_SIZE);
    //Note that timecoder_init will not double-malloc the LUTs, and after this we are guaranteed
    //that the LUT has been generated unless we ran out of memory.
    s_bLUTInitialized = true;
    m_uiSafeZone = timecoder_get_safe(&timecoder);
    //}
    s_xwaxLUTMutex.unlock();

    qDebug() << "Starting vinyl control xwax thread";
}